Skip to content

Fix for ONC profiles losing their details when adding another profile - #45299

Merged
getvictor merged 2 commits into
mainfrom
victor/42405-onc-details
May 12, 2026
Merged

Fix for ONC profiles losing their details when adding another profile#45299
getvictor merged 2 commits into
mainfrom
victor/42405-onc-details

Conversation

@getvictor

@getvictor getvictor commented May 12, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #42405

Unreleased bug fix.

Checklist for submitter

Testing

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

Summary by CodeRabbit

  • Bug Fixes

    • Android MDM profile detail messages (e.g., certificate status) are preserved when adding additional profiles or marking profiles pending, preventing loss of important status information.
  • Tests

    • Added an integration test verifying ONC/certificate detail is retained when additional Android MDM profiles are uploaded for the same team.

Review Change Stack

@getvictor
getvictor requested a review from Copilot May 12, 2026 21:23
@getvictor

Copy link
Copy Markdown
Member Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@getvictor

Copy link
Copy Markdown
Member Author

/agentic_review

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented May 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Remediation recommended

1. Stale detail after reset ✓ Resolved 🐞 Bug ≡ Correctness
Description
When bulk-resetting Android host profiles to pending, `bulkUpsertMDMAndroidHostProfiles(...,
updateDetail=false) omits detail from the ON DUPLICATE KEY UPDATE` clause, so existing rows can
keep an old detail message while status is reset to NULL (pending). Because
GetHostMDMAndroidProfiles coalesces NULL status to "pending" but returns detail as-is, API/UI
consumers can see a pending profile with an outdated failure/detail message until the reconciler
rewrites it.
Code

server/datastore/mysql/android.go[R1195-1206]

+	detailUpdate := "detail = VALUES(detail),"
+	if !updateDetail {
+		// detail intentionally omitted from the ON DUPLICATE KEY UPDATE clause:
+		// the reconciler owns this field and may carry a forward-looking message
+		// (e.g. "Waiting for certificate ..." on withheld ONC profiles) that
+		// must survive this state reset.
+		detailUpdate = ""
+	}
+
  executeUpsertBatch := func(valuePart string, args []any) error {
  	stmt := fmt.Sprintf(`
  		INSERT INTO host_mdm_android_profiles (
Evidence
The reset path now avoids updating detail (so old messages persist) while status is reset to
NULL; the host profiles read path coalesces NULL status to "pending" but returns detail, meaning
callers can observe a pending status with stale detail. The reconciler can populate non-empty
detail messages on failures, so preserving detail across unrelated resets can surface outdated
failure messages until the next reconcile.

server/datastore/mysql/android.go[1185-1231]
server/datastore/mysql/android.go[1271-1294]
server/datastore/mysql/android.go[1460-1481]
server/datastore/mysql/android.go[1551-1601]
server/mdm/android/service/profiles.go[205-250]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Android host profile resets intentionally preserve `detail` to keep ONC withholding messages, but this also preserves unrelated stale details (e.g. prior failure messages) while status is reset to NULL (pending).
## Issue Context
- Reset-to-pending paths now omit `detail` updates for existing rows.
- The host profiles API returns `detail` even when `status` is NULL (treated as pending).
- The reconciler writes non-empty `detail` strings for failures.
## Fix Focus Areas
- server/datastore/mysql/android.go[1185-1269]
- server/datastore/mysql/android.go[1460-1481]
- server/datastore/mysql/android.go[1551-1601]
## Suggested fix
Update the reset logic to preserve `detail` only for ONC-withheld rows (e.g. those whose `detail` starts with `fleet.ONCProfileWithheldDetailPrefix`), while clearing/updating `detail` for all other profiles during the reset.
Concretely, instead of fully omitting `detail` from `ON DUPLICATE KEY UPDATE` when `updateDetail=false`, use a conditional assignment such as:
- `detail = IF(detail LIKE 'Waiting for certificate%', detail, VALUES(detail))`
- with `VALUES(detail)` being `''` in reset payloads, this clears non-ONC stale details while preserving ONC withholding.
Apply the same conditional behavior to `updateIncludedInPolicyVersionStmt` if it also needs to preserve ONC-withheld detail without retaining stale error detail for other profiles.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

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: ffb4d048-5436-40e8-9e9f-9ee39726f59e

📥 Commits

Reviewing files that changed from the base of the PR and between 0e2a2db and ae46bb7.

📒 Files selected for processing (2)
  • server/datastore/mysql/android.go
  • server/service/integration_android_certificate_templates_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/service/integration_android_certificate_templates_test.go

Walkthrough

This PR makes the Android host-profile bulk upsert optionally preserve the detail column by adding an internal bulkUpsertMDMAndroidHostProfiles(helper) with a preserveExistingDetail flag and interpolating a conditional SQL fragment. Call sites that mark profiles pending no longer clear detail and invoke the helper with preservation enabled (subquery selection tightened by team). An integration test verifies withheld ONC profiles keep their certificate-waiting detail while their status is reset when additional profiles are added.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is minimal and does not adequately follow the provided template. While it cites the related issue #42405 and mentions testing and manual QA, most checklist items are unchecked or incomplete, and critical sections are missing or unfilled. Expand the description to check applicable template items: specify changes made (database, API, GitOps), confirm security/validation measures, document testing scope, and note any schema migration or load testing implications per the template.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarizes the main issue fixed: ONC profiles losing their details when another profile is added, which aligns with the core bug and the refactoring to preserve details in the datastore layer.
Linked Issues check ✅ Passed The code changes align with the primary objectives from #42405: the datastore refactoring preserves ONC profile details during updates, the new test verifies detail preservation, and the implementation addresses the core fix to prevent details from being lost when adding another profile.
Out of Scope Changes check ✅ Passed All changes are directly scoped to the linked issue #42405. The datastore layer refactoring, internal helper methods, and integration test are all focused on fixing the detail preservation bug without introducing unrelated modifications.

✏️ 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 victor/42405-onc-details

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
server/datastore/mysql/android.go (1)

1463-1474: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Scope the reset to the current team.

This subquery matches incoming profiles by name only, so updating team A can reset host_mdm_android_profiles rows for team B if both teams have a profile with the same name. Please include the current profileTeamID/no-team scope in the subquery. As per coding guidelines: "ensure that appropriate filtering criteria are applied—especially when a query is intended to return data for a specific entity."

Suggested fix
 	WHERE
-		profile_uuid IN (SELECT profile_uuid FROM mdm_android_configuration_profiles WHERE name IN (?))
+		profile_uuid IN (
+			SELECT profile_uuid
+			FROM mdm_android_configuration_profiles
+			WHERE team_id = ? AND name IN (?)
+		)
 	`
-	stmt, args, err = sqlx.In(updateIncludedInPolicyVersionStmt, incomingNames)
+	stmt, args, err = sqlx.In(updateIncludedInPolicyVersionStmt, profileTeamID, incomingNames)
🤖 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/android.go` around lines 1463 - 1474, The UPDATE's
subquery (in updateIncludedInPolicyVersionStmt) only matches profiles by name
and can touch other teams; restrict the subquery on
mdm_android_configuration_profiles to the current team's scope by adding a
filter on the profile team identifier (use the same profileTeamID/no-team logic
the codebase uses) so the subquery becomes something like "SELECT profile_uuid
FROM mdm_android_configuration_profiles WHERE name IN (?) AND (team_id = ? OR
(team_id IS NULL AND ? IS NULL))" and ensure the caller passes profileTeamID (or
equivalent) as the additional parameter(s) so only profiles for the current team
(or no-team when appropriate) are affected.
🤖 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.

Outside diff comments:
In `@server/datastore/mysql/android.go`:
- Around line 1463-1474: The UPDATE's subquery (in
updateIncludedInPolicyVersionStmt) only matches profiles by name and can touch
other teams; restrict the subquery on mdm_android_configuration_profiles to the
current team's scope by adding a filter on the profile team identifier (use the
same profileTeamID/no-team logic the codebase uses) so the subquery becomes
something like "SELECT profile_uuid FROM mdm_android_configuration_profiles
WHERE name IN (?) AND (team_id = ? OR (team_id IS NULL AND ? IS NULL))" and
ensure the caller passes profileTeamID (or equivalent) as the additional
parameter(s) so only profiles for the current team (or no-team when appropriate)
are affected.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 49f29d6a-21cf-4ad2-83fb-109194aa016c

📥 Commits

Reviewing files that changed from the base of the PR and between f67e13a and 0e2a2db.

📒 Files selected for processing (2)
  • server/datastore/mysql/android.go
  • server/service/integration_android_certificate_templates_test.go

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

Note

Copilot was unable to run its full agentic suite in this review.

Adds coverage and datastore changes to prevent Android ONC profiles from losing their detail message (e.g. “Waiting for certificate ...”) when additional profiles are added to the same team.

Changes:

  • Adds an integration regression test asserting ONC profile detail is preserved when adding another Android profile.
  • Adjusts Android host profile upsert/reset logic to preserve detail while resetting status to NULL.
  • Stops clearing detail in the “mark for reprocessing” update path so reconciler-owned messages survive state resets.

Reviewed changes

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

File Description
server/service/integration_android_certificate_templates_test.go Adds an integration test to ensure ONC withheld detail is not wiped when adding another profile.
server/datastore/mysql/android.go Preserves detail during “pending reset” / reprocessing updates and adds an internal upsert helper to control whether detail is updated.

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

Comment thread server/service/integration_android_certificate_templates_test.go Outdated
Comment thread server/datastore/mysql/android.go
@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.81818% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.74%. Comparing base (393007e) to head (ae46bb7).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
server/datastore/mysql/android.go 81.81% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #45299      +/-   ##
==========================================
+ Coverage   66.72%   66.74%   +0.02%     
==========================================
  Files        2732     2732              
  Lines      218476   218486      +10     
  Branches    10706    10706              
==========================================
+ Hits       145770   145824      +54     
+ Misses      59496    59461      -35     
+ Partials    13210    13201       -9     
Flag Coverage Δ
backend 68.58% <81.81%> (+0.02%) ⬆️

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.

@getvictor
getvictor marked this pull request as ready for review May 12, 2026 22:06
@getvictor
getvictor requested a review from a team as a code owner May 12, 2026 22:06

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

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.

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

Don't love the trailing boolean flag, but the other way to fix this would be to distinguish between ONC-withheld profiles and regular profiles and only preserve detail for the former? Which seems much more complicated.

@getvictor
getvictor merged commit 7e3dea6 into main May 12, 2026
53 of 56 checks passed
@getvictor
getvictor deleted the victor/42405-onc-details branch May 12, 2026 22:47
@coderabbitai coderabbitai Bot mentioned this pull request May 27, 2026
8 tasks
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.

Android: deploy Wi-Fi configuration profile after certificate is deployed

3 participants