Skip to content

Add patch policy and software automation usage statistics - #50766

Draft
cdcme wants to merge 2 commits into
mainfrom
feat-50762-usage-stats-patch-policies
Draft

Add patch policy and software automation usage statistics#50766
cdcme wants to merge 2 commits into
mainfrom
feat-50762-usage-stats-patch-policies

Conversation

@cdcme

@cdcme cdcme commented Aug 7, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #50762

Adds the usage statistics documented in #49980 (merged to docs-v4.91.0):

  • numPoliciesAutomationEnabledSoftware — the number of policies with a software automation.
  • fleetMaintainedAppsMacOS / fleetMaintainedAppsWindows — each entry changes from a slug string to { name, patchPolicy, softwareAutomation }.

Notes for review:

  • The count reuses Fleet's existing definition of a software automation rather than inventing one. The predicate behind automation_type=software is extracted from createAutomationClause into policiesSoftwareAutomationClause and shared, so the stat can't drift from what the API returns. The reconstructed SQL is byte-identical to the previous literal.
  • The per-app softwareAutomation is deliberately narrower — it means "this patch policy also carries an install-software automation." Using the shared clause here would make it identical to patchPolicy (every matched policy is type='patch'), so the field would carry no information.
  • The FMA query needs GROUP BY + MAX(...): one slug backs up to 2 × N_teams installer rows (cached versions plus per-team rows). The old SELECT DISTINCT collapsed those only because every row was identical; with per-team booleans it would emit duplicate slugs.
  • No database migration.

Important

Depends on #50760, which must ship first. fleetdm.com currently declares these two fields as type: ['string']. Sails rejects an array of objects against that declaration with E_INVALID, which becomes an E_INVALID_ARGINS → 400 for the whole request — so until #50760 lands, an upgraded server would have its entire usage statistics payload dropped, not just these fields.

Checklist for submitter

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

  • 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

Automated coverage:

  • TestStatistics/FleetMaintainedAppsInUse — patch policy with and without a software automation, a dynamic policy on the same title, the same app on a second team (asserting one entry per slug), and a team-scoped patch policy that must not apply to another team's installer.
  • TestStatistics/PoliciesAutomationEnabledSoftware — installer and VPP automations count; script and calendar automations don't; a patch policy counts even with no install automation, pinning parity with automation_type=software.
  • TestMaybeSendStatistics — pins the serialized payload against the shape published in [Docs] Usage stats changes #49980.
  • TestListTeamPoliciesAutomationTypeSoftware — unchanged behaviour after extracting the shared clause.

Both new predicates were mutation-tested: removing OR p.type = 'patch' or the team-scoping predicate each fails a test rather than passing silently.

End-to-end QA is left unchecked deliberately — it can't be completed until #50760 is deployed, since the receiving webhook would reject the new payload today.

Summary by CodeRabbit

  • New Features

    • Statistics now report the number of policies with software automation enabled.
    • Fleet-maintained macOS and Windows app reports now include patch-policy and software-automation status.
    • App usage data is grouped by platform and provides clearer policy coverage details.
  • Bug Fixes

    • Improved statistics accuracy for duplicate installers, team scoping, and different policy types.

@codecov

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.87097% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.41%. Comparing base (5a1365d) to head (6bdc250).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
server/datastore/mysql/statistics.go 87.50% 1 Missing and 2 partials ⚠️
server/datastore/mysql/policies.go 71.42% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main   #50766   +/-   ##
=======================================
  Coverage   68.40%   68.41%           
=======================================
  Files        3963     3963           
  Lines      255174   255194   +20     
  Branches    13420    13420           
=======================================
+ Hits       174560   174591   +31     
+ Misses      65016    65008    -8     
+ Partials    15598    15595    -3     
Flag Coverage Δ
backend 69.62% <83.87%> (+<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.

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 updates the Fleet server’s usage statistics payload to include new patch-policy/software-automation metrics and to enrich the Fleet-maintained-apps stats from simple slug arrays into structured per-app objects (matching the shape documented in the related issue/docs work).

Changes:

  • Change fleetMaintainedAppsMacOS / fleetMaintainedAppsWindows from []string to []FleetMaintainedAppUsage{name, patchPolicy, softwareAutomation} in the statistics payload.
  • Add numPoliciesAutomationEnabledSoftware, derived from the same predicate as the public automation_type=software filter by extracting it into policiesSoftwareAutomationClause.
  • Update the MySQL statistics query to properly aggregate per-slug results (via GROUP BY + MAX(...)) and expand tests to cover the new behavior and payload shape.

Reviewed changes

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

Show a summary per file
File Description
server/fleet/statistics.go Adds the new usage-stat struct/type changes and introduces the new numPoliciesAutomationEnabledSoftware field.
server/datastore/mysql/statistics.go Populates the new statistics fields; updates the FMA “in use” query to return per-app objects with aggregated booleans.
server/datastore/mysql/statistics_test.go Adds/extends tests for FMA usage object shape and the new “policies automation enabled (software)” count.
server/datastore/mysql/policies.go Extracts and reuses the automation_type=software predicate via policiesSoftwareAutomationClause; adds the DB count helper.
cmd/fleet/serve_test.go Updates the pinned serialized usage-stats JSON payload to the new field shapes and adds the new numeric stat.
Files excluded by content exclusion policy (1)
  • changes/50762-usage-stats-patch-policies.md

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

@cdcme
cdcme marked this pull request as ready for review August 7, 2026 14:53
@cdcme
cdcme requested a review from a team as a code owner August 7, 2026 14:53
@cdcme
cdcme marked this pull request as draft August 7, 2026 14:53
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The statistics payload now includes NumPoliciesAutomationEnabledSoftware. Fleet-maintained macOS and Windows apps now use structured records with names and patch-policy and software-automation flags. MySQL queries count applicable policies and aggregate app usage by platform, app slug, and team-scoped policy data. Tests cover policy types, duplicate installers, patch policies, software automation, team scope, and JSON serialization.

Possibly related issues

  • fleetdm/fleet#50761: Directly covers the new patch-policy and software-automation statistics.
  • fleetdm/fleet#50760: Defines parsing and storage requirements for the new statistics fields and structured app objects.
  • fleetdm/fleet#48005: Covers the usage statistics implemented by this change.

Possibly related PRs

  • fleetdm/fleet#49691: Adds related Fleet-maintained app patch-policy handling used by the new statistics.
  • fleetdm/fleet#49871: Shares patch-policy handling relevant to the reported patch-policy metadata.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the addition of patch policy and software automation usage statistics.
Description check ✅ Passed The description identifies the linked issue, explains the payload changes and dependency, and documents automated testing; the unchecked manual QA is justified.
Linked Issues check ✅ Passed The implementation adds the required count and structured app statistics, preserves the no-migration requirement, and documents the dependency on #50760.
Out of Scope Changes check ✅ Passed The reviewed changes support the linked issue through statistics logic, shared SQL predicates, payload updates, and focused automated tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 feat-50762-usage-stats-patch-policies

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.

@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: 1

🧹 Nitpick comments (2)
server/datastore/mysql/statistics.go (1)

332-334: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Correct the comment about empty-slice serialization.

The comment states that the slices serialize as [] instead of null. The payload fields FleetMaintainedAppsMacOS and FleetMaintainedAppsWindows in server/fleet/statistics.go use omitempty, so an empty slice is omitted from the JSON entirely. The make calls still matter for callers and tests that assert non-nil, but the stated reason is wrong.

📝 Proposed comment fix
-	// Initialize as empty slices (not nil) so they serialize as [] instead of null
+	// Initialize as empty slices (not nil) so callers get a non-nil result. Note the payload
+	// fields use omitempty, so empty slices are omitted from the statistics JSON.
 	macOSApps = make([]fleet.FleetMaintainedAppUsage, 0)
 	windowsApps = make([]fleet.FleetMaintainedAppUsage, 0)
🤖 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/statistics.go` around lines 332 - 334, Update the
comment above the macOSApps and windowsApps initializations to state that the
slices are deliberately non-nil for callers and tests, rather than claiming they
serialize as [] instead of null. Keep both make calls unchanged.
server/datastore/mysql/statistics_test.go (1)

928-937: 🔒 Security & Privacy | 🔵 Trivial

Suppress the G202 SQL string-concatenation finding.

This fmt.Sprintf is used only in tests with hard-coded column/value fragments and ? data binding; add a targeted //nolint:gosec // G202 comment with a matching reason to keep lint noise down.

🤖 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/statistics_test.go` around lines 928 - 937, Suppress
the targeted gosec G202 finding on the fmt.Sprintf SQL construction inside
insertPolicy by adding a //nolint:gosec comment with a reason noting that the
query fragments are hard-coded test values and data remains parameter-bound.

Source: Linters/SAST tools

🤖 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 `@server/datastore/mysql/statistics_test.go`:
- Line 886: Correct the setup comment near the test fixture to state that it
creates only a software installer, then extend the test’s policy setup and
assertions around policiesSoftwareAutomationClause to include a policy with
vpp_apps_teams_id populated. Ensure the added fixture exercises the
vpp_apps_teams_id branch alongside the existing software_installer_id and patch
branches.

---

Nitpick comments:
In `@server/datastore/mysql/statistics_test.go`:
- Around line 928-937: Suppress the targeted gosec G202 finding on the
fmt.Sprintf SQL construction inside insertPolicy by adding a //nolint:gosec
comment with a reason noting that the query fragments are hard-coded test values
and data remains parameter-bound.

In `@server/datastore/mysql/statistics.go`:
- Around line 332-334: Update the comment above the macOSApps and windowsApps
initializations to state that the slices are deliberately non-nil for callers
and tests, rather than claiming they serialize as [] instead of null. Keep both
make calls unchanged.
🪄 Autofix

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 Plus

Run ID: 23c5622f-9eee-4863-b116-64f3e181fe58

📥 Commits

Reviewing files that changed from the base of the PR and between f656ac5 and 6bdc250.

⛔ Files ignored due to path filters (1)
  • changes/50762-usage-stats-patch-policies.md is excluded by !**/*.md
📒 Files selected for processing (5)
  • cmd/fleet/serve_test.go
  • server/datastore/mysql/policies.go
  • server/datastore/mysql/statistics.go
  • server/datastore/mysql/statistics_test.go
  • server/fleet/statistics.go

require.NoError(t, err)
assert.Equal(t, 0, count)

// Set up an installer and a VPP app so the automation columns can be populated.

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the inaccurate comment and add coverage for vpp_apps_teams_id.

Line 886 states that the fixture sets up "an installer and a VPP app". The test creates only a software installer. No VPP app is created, and no policy sets vpp_apps_teams_id.

policiesSoftwareAutomationClause has three branches: software_installer_id, vpp_apps_teams_id, and type = 'patch'. This test covers two of them. A regression that drops the vpp_apps_teams_id term would not fail any test here.

Correct the comment, and add a policy that sets vpp_apps_teams_id so the third branch is exercised.

📝 Proposed comment correction
-	// Set up an installer and a VPP app so the automation columns can be populated.
+	// Set up a software installer so the automation columns can be populated.

I can generate the VPP app fixture and the extra assertion if you want.

Also applies to: 939-956

🤖 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/statistics_test.go` at line 886, Correct the setup
comment near the test fixture to state that it creates only a software
installer, then extend the test’s policy setup and assertions around
policiesSoftwareAutomationClause to include a policy with vpp_apps_teams_id
populated. Ensure the added fixture exercises the vpp_apps_teams_id branch
alongside the existing software_installer_id and patch branches.

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.

Send new patch policy and software automation statistics from the Fleet server

2 participants