Skip to content

Emit failed VPP/in-house install activity, release reserved license - #46332

Merged
cdcme merged 9 commits into
mainfrom
fix-45854-failed-install-activity
May 28, 2026
Merged

Emit failed VPP/in-house install activity, release reserved license#46332
cdcme merged 9 commits into
mainfrom
fix-45854-failed-install-activity

Conversation

@cdcme

@cdcme cdcme commented May 28, 2026

Copy link
Copy Markdown
Member

Related issue:

Resolves #45851, #45854

Fixes three things:

  1. Failed installs now show up. An iOS/iPadOS VPP or in-house install whose managed-config references an IdP variable the host can't supply (e.g. $FLEET_VAR_HOST_END_USER_IDP_DEPARTMENT) used to return HTTP 400 (admin) or fail silently (self-service / auto). It now records a failed activity with the specific unresolvable variable as the reason.

  2. No license leak on that path. Fleet checks the variables before calling AssociateAssets, so no seat is reserved for installs that won't go through.

  3. General license-leak fix. Added vpp.DisassociateAssets and call it on post-association failures and on cancel of a pending VPP install — so any reserved-but-not-used seat gets released.

The check goes in InstallVPPAppPostValidation, the one place every VPP install path passes through (admin, self-service, policy, auto-update, setup experience, worker). The reason goes in the activity's existing JSON details so we didn't have to add a migration. Known follow-up: the Host > Software tab modal still says "Install details are no longer available" — it opens from inventory, not the activity, so it doesn't see the reason. The activity feed click works.

Screenshot 2026-05-28 at 10 32 03 Screenshot 2026-05-28 at 10 31 55 Screenshot 2026-05-28 at 10 31 16 Screenshot 2026-05-28 at 10 30 56

Checklist for submitter

Testing

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

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

Summary by CodeRabbit

  • New Features

    • Pre‑flight validation of managed app configuration variables; unresolved vars are recorded as failed installs and shown with actor-aware failure messages plus a collapsible “Error details” view.
    • Activity UI now surfaces actor metadata and install-origin flags (Fleet vs. end user, self‑service, setup/auto-update).
  • Bug Fixes

    • Safer VPP seat handling: best‑effort disassociation on failed or canceled installs to reduce license leaks.
  • Tests

    • Added tests covering failure messaging, pre‑flight failure handling, and VPP disassociation behavior.

Review Change Stack

@cdcme
cdcme force-pushed the fix-45854-failed-install-activity branch from 6766c37 to 0fabaa8 Compare May 28, 2026 13:55
@codecov

codecov Bot commented May 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 55.78035% with 153 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.88%. Comparing base (7c33552) to head (9efa152).
⚠️ Report is 11 commits behind head on main.

Files with missing lines Patch % Lines
ee/server/service/software_installers.go 46.66% 33 Missing and 7 partials ⚠️
server/datastore/mysql/in_house_apps.go 16.21% 31 Missing ⚠️
server/service/activities.go 32.50% 21 Missing and 6 partials ⚠️
...allDetailsModal/SoftwareIpaInstallDetailsModal.tsx 33.33% 13 Missing and 1 partial ⚠️
server/datastore/mysql/vpp.go 86.66% 10 Missing and 4 partials ⚠️
server/mdm/apple/install_application.go 38.46% 8 Missing ⚠️
server/mdm/apple/vpp/api.go 46.66% 4 Missing and 4 partials ⚠️
.../VppInstallDetailsModal/VppInstallDetailsModal.tsx 71.42% 5 Missing and 1 partial ⚠️
.../DashboardPage/cards/ActivityFeed/ActivityFeed.tsx 50.00% 3 Missing ⚠️
.../hosts/details/HostDetailsPage/HostDetailsPage.tsx 0.00% 1 Missing ⚠️
... and 1 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #46332      +/-   ##
==========================================
- Coverage   66.89%   66.88%   -0.02%     
==========================================
  Files        2782     2784       +2     
  Lines      221734   222108     +374     
  Branches    11356    11243     -113     
==========================================
+ Hits       148334   148554     +220     
- Misses      59999    60123     +124     
- Partials    13401    13431      +30     
Flag Coverage Δ
backend 68.65% <56.56%> (-0.02%) ⬇️
frontend 56.26% <51.02%> (-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.

@cdcme

cdcme commented May 28, 2026

Copy link
Copy Markdown
Member Author

@claude review once

Comment thread server/datastore/mysql/vpp.go
Comment thread ee/server/service/software_installers.go
Comment thread server/fleet/activities.go Outdated
@cdcme

cdcme commented May 28, 2026

Copy link
Copy Markdown
Member Author

@claude review once

@cdcme
cdcme marked this pull request as ready for review May 28, 2026 15:55
@cdcme
cdcme requested a review from a team as a code owner May 28, 2026 15:55
Copilot AI review requested due to automatic review settings May 28, 2026 15:55
@cdcme
cdcme requested a review from a team as a code owner May 28, 2026 15:55

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

Comment thread server/service/activities.go
Comment thread ee/server/service/software_installers.go
Comment thread server/mdm/apple/install_application.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

This PR improves iOS/iPadOS VPP and in-house app install failure handling by recording Fleet-side pre-flight failures as failed install activities (instead of rejecting/silently failing), and by preventing/reclaiming reserved VPP license seats to avoid leaks. It also updates the UI install-details modals to display actor-specific failure copy and surface the failure reason for these Fleet-side failures.

Changes:

  • Record pre-flight managed-config substitution failures as failed install activities (VPP and in-house), without enqueueing an MDM command or creating zombie upcoming activities.
  • Add VPP license seat release via DisassociateAssets on post-association failures and on cancel of a pending VPP install.
  • Update activity-feed driven install-details modals to render actor-driven failure messaging and show Fleet-side failure reasons.

Reviewed changes

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

Show a summary per file
File Description
server/service/integration_mdm_test.go Extends VPP mock server to capture /assets/disassociate calls for license-release assertions.
server/service/integration_apple_vpp_config_test.go Adds integration coverage for pre-flight VPP failures being recorded (not 400), and for license release on cancel.
server/service/activities.go Releases reserved VPP seats when canceling a VPP install activity.
server/mock/datastore_mock.go Adds mock datastore hooks for recording failed installs and fetching cancel-release info.
server/mdm/apple/vpp/api.go Adds DisassociateAssets support for releasing VPP seat reservations.
server/mdm/apple/install_application.go Introduces a typed unresolvable-variable error to preserve per-variable failure details.
server/fleet/vpp.go Adds VPPInstallReleaseInfo data model for cancel-time seat-release decisions.
server/fleet/datastore.go Extends datastore interface for recording Fleet-side failed installs and cancel-release lookups.
server/fleet/activities.go Adds failure_reason to install activity detail payloads.
server/datastore/mysql/vpp.go Implements Fleet-side failed VPP install recording and cancel-release info query; adjusts summary SQL to include pre-flight failures.
server/datastore/mysql/software_installers.go Adjusts status queries/joins to include Fleet-side pre-flight failures for VPP and in-house installs.
server/datastore/mysql/in_house_apps.go Adjusts past-activity query joins and adds failed in-house install recording helper.
frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx Passes actor/envelope fields + failure reason into install-details modals from host activity feed.
frontend/pages/DashboardPage/cards/ActivityFeed/ActivityFeed.tsx Passes actor/envelope fields + failure reason into install-details modals from global activity feed.
frontend/interfaces/activity.ts Adds from_auto_update and failure_reason fields to activity details typing.
frontend/components/ActivityItem/ActivityItem.tsx Includes actor_full_name / fleet_initiated in the details-click payload.
frontend/components/ActivityDetails/InstallDetails/VppInstallDetailsModal/VppInstallDetailsModal.tsx Renders actor-driven failure copy + Details section for Fleet-side pre-flight failures; skips command-result fetch when applicable.
frontend/components/ActivityDetails/InstallDetails/VppInstallDetailsModal/VppInstallDetailsModal.tests.tsx Adds unit tests for actor-driven failure message logic in VPP modal.
frontend/components/ActivityDetails/InstallDetails/SoftwareIpaInstallDetailsModal/SoftwareIpaInstallDetailsModal.tsx Mirrors VPP modal behavior for Fleet-side pre-flight failures for in-house (.ipa) installs.
ee/server/service/software_installers.go Adds pre-flight substitution checks + failed-install recording for VPP and in-house install paths; disassociates on post-association failures.
ee/server/service/install_vpp_associate_test.go Updates unit test setup to account for new pre-flight configuration lookup.

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

Comment thread server/datastore/mysql/vpp.go Outdated
Comment thread server/service/activities.go
@coderabbitai

coderabbitai Bot commented May 28, 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: d16cc0ec-a0bd-483b-97cb-9882a39886f5

📥 Commits

Reviewing files that changed from the base of the PR and between 93e7abb and 9efa152.

📒 Files selected for processing (2)
  • frontend/interfaces/activity.ts
  • frontend/pages/DashboardPage/cards/ActivityFeed/ActivityFeed.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/pages/DashboardPage/cards/ActivityFeed/ActivityFeed.tsx

Walkthrough

This PR adds pre-flight checks for Apple managed-app-configuration Fleet variables and a typed UnresolvableAppConfigVarError; records failed VPP and in-house installs (sets verification_failed_at and emits activities with failureReason); updates datastore interfaces and SQL joins so failed-install rows are visible without nano_command_results; introduces VPP DisassociateAssets and best-effort seat-release on insertion failure and cancel; extends mocks and integration tests; and threads failureReason and actor metadata through the frontend activity feed and install-details modals.

Possibly related issues

  • #45851: This PR implements emitting failed-install activities with actor-specific copy and exposing the unresolved variable reason in Install Details instead of returning HTTP 400.

Possibly related PRs

  • fleetdm/fleet#44935: Overlaps on Apple managed-app-configuration Fleet-variable substitution changes consumed by this PR.
  • fleetdm/fleet#45452: Related VPP install handling for unresolvable managed-app-configuration variables; this PR records failures and surfaces them to UI.
  • fleetdm/fleet#46108: Related work in the VPP associate-assets flow; this PR adds stored-associate tracking and disassociate cleanup on failure.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description includes the related issue numbers (#45851, #45854), explains the three key fixes, details the implementation approach, and covers testing. However, the submitter did not complete the full template checklist regarding changes files, validation, security, database migrations, or fleetd/orbit compatibility. Complete the checklist by verifying and checking the applicable boxes for validation, database/schema changes, changes files, and other relevant items from the template.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: emitting a failed activity for VPP/in-house installs and releasing reserved licenses on cancellation.
Linked Issues check ✅ Passed The PR implements all coding requirements from #45851: records failed activities with reason details, prevents pre-association failures, supports actor-specific messaging, and enables the Install Details modal to display the unresolvable variable reason.
Out of Scope Changes check ✅ Passed All changes are directly tied to the linked issues. The PR adds necessary infrastructure (error types, datastore methods, VPP API support, UI updates) to emit failed install activities, store failure reasons, and release VPP seats—with no unrelated modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ 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 fix-45854-failed-install-activity

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

Caution

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

⚠️ Outside diff range comments (2)
frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx (1)

799-877: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Thread IPA pre-flight fields all the way into the modal props.

You correctly store failureReason, actorFullName, fleetInitiated, and selfService here, but they’re dropped before render on the IPA modal path (Line 1799+), so this flow won’t show actor-specific failed-install copy or error details.

Proposed fix
           {ipaPackageInstallDetails && (
             <SoftwareIpaInstallDetailsModal
               details={{
                 appName: ipaPackageInstallDetails.appName || "",
                 fleetInstallStatus: (ipaPackageInstallDetails.fleetInstallStatus ||
                   "pending_install") as SoftwareInstallUninstallStatus,
                 hostDisplayName: ipaPackageInstallDetails.hostDisplayName || "",
                 commandUuid: ipaPackageInstallDetails.commandUuid || "",
+                failureReason: ipaPackageInstallDetails.failureReason,
+                actorFullName: ipaPackageInstallDetails.actorFullName,
+                fleetInitiated: ipaPackageInstallDetails.fleetInitiated,
+                selfService: ipaPackageInstallDetails.selfService,
               }}
               onCancel={onCancelIpaSoftwareInstallDetailsModal}
             />
           )}
🤖 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 `@frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx` around
lines 799 - 877, The onShowActivityDetails handler stores failureReason,
actorFullName, fleetInitiated, and selfService into ipa package state via
setIpaPackageInstallDetails, but those fields are not forwarded into the IPA
install modal when rendering; update the ipa package state shape (used by
setIpaPackageInstallDetails) to include these four fields and then pass them
through to the IPA modal component props (the component that consumes
ipaPackageInstallDetails in the render path), so the modal receives
failureReason, actorFullName, fleetInitiated, and selfService for display.
server/datastore/mysql/in_house_apps.go (1)

69-81: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Mirror managed app configuration updates to both .ipa rows.

This insert path now establishes that one .ipa needs identical config under both the iOS and iPadOS installer IDs, but SaveInHouseAppUpdates still sets/clears configuration only for payload.InstallerID. After an edit, one platform can keep stale config while the other gets the new value, so pre-flight validation and install behavior will diverge by platform.

🤖 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/in_house_apps.go` around lines 69 - 81,
SaveInHouseAppUpdates currently updates/clears configuration only for
payload.InstallerID, which leaves the paired .ipa row (iPadOS or iOS) stale;
change SaveInHouseAppUpdates to mirror configuration changes to both installer
IDs by calling ds.updateInHouseAppConfigurationTx (or the same transaction-based
helper used elsewhere) for both installerID and installerIDIpad (or compute the
counterpart ID the same way the insert path does) so that when
payload.Configuration is non-empty or being cleared the update is applied to
both rows.
🤖 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/in_house_apps.go`:
- Around line 783-818: RecordFailedInHouseAppInstall currently skips the
existence checks used by InsertHostInHouseAppInstall: before inserting,
explicitly verify the host exists (same guard used in
InsertHostInHouseAppInstall) and after tx.ExecContext(insStmt, ...) check the
sql.Result.RowsAffected(); if 0 treat it as not found and return a
notFound("install_command") style error instead of proceeding to build the
activity. Make these checks inside the ds.withRetryTxx transaction, and only
call ds.getPastActivityDataForInHouseAppInstallDB (and return user/act) when the
insert reported RowsAffected()>0.

In `@server/datastore/mysql/vpp.go`:
- Around line 1412-1437: RecordFailedVPPAppInstall currently inserts a failed
VPP install without validating host existence; mirror the guard used in
InsertHostVPPSoftwareInstall by checking the host exists (using the same
lookup/validation logic that InsertHostVPPSoftwareInstall uses) before running
the INSERT, and return the same error/behavior when the host is missing or
stale; locate the host existence check in InsertHostVPPSoftwareInstall and apply
the same pattern around hostID in RecordFailedVPPAppInstall so callers get
consistent failures.

In `@server/service/activities.go`:
- Around line 209-214: You’re hard-coding PricingParam: "STDQ" in the
vpp.DisassociateAssetsRequest which can mismatch the original association and
cause disassociation to fail; update the code that builds the request in
activities.go to use the actual pricing tier from the stored association/asset
metadata (the same field that was saved when the seat was reserved) instead of
"STDQ" — e.g. read the stored pricing param linked to info.AdamID (or the asset
record tied to the reservation) and set Assets: []vpp.Asset{{AdamID:
info.AdamID, PricingParam: storedPricingParam}}, and if no metadata exists, omit
or pass an empty PricingParam so VPP can infer the correct tier.

---

Outside diff comments:
In `@frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx`:
- Around line 799-877: The onShowActivityDetails handler stores failureReason,
actorFullName, fleetInitiated, and selfService into ipa package state via
setIpaPackageInstallDetails, but those fields are not forwarded into the IPA
install modal when rendering; update the ipa package state shape (used by
setIpaPackageInstallDetails) to include these four fields and then pass them
through to the IPA modal component props (the component that consumes
ipaPackageInstallDetails in the render path), so the modal receives
failureReason, actorFullName, fleetInitiated, and selfService for display.

In `@server/datastore/mysql/in_house_apps.go`:
- Around line 69-81: SaveInHouseAppUpdates currently updates/clears
configuration only for payload.InstallerID, which leaves the paired .ipa row
(iPadOS or iOS) stale; change SaveInHouseAppUpdates to mirror configuration
changes to both installer IDs by calling ds.updateInHouseAppConfigurationTx (or
the same transaction-based helper used elsewhere) for both installerID and
installerIDIpad (or compute the counterpart ID the same way the insert path
does) so that when payload.Configuration is non-empty or being cleared the
update is applied to both rows.
🪄 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: 10611de3-95ef-42a1-8304-81eb289ec445

📥 Commits

Reviewing files that changed from the base of the PR and between 7c33552 and 05b48bf.

📒 Files selected for processing (21)
  • ee/server/service/install_vpp_associate_test.go
  • ee/server/service/software_installers.go
  • frontend/components/ActivityDetails/InstallDetails/SoftwareIpaInstallDetailsModal/SoftwareIpaInstallDetailsModal.tsx
  • frontend/components/ActivityDetails/InstallDetails/VppInstallDetailsModal/VppInstallDetailsModal.tests.tsx
  • frontend/components/ActivityDetails/InstallDetails/VppInstallDetailsModal/VppInstallDetailsModal.tsx
  • frontend/components/ActivityItem/ActivityItem.tsx
  • frontend/interfaces/activity.ts
  • frontend/pages/DashboardPage/cards/ActivityFeed/ActivityFeed.tsx
  • frontend/pages/hosts/details/HostDetailsPage/HostDetailsPage.tsx
  • server/datastore/mysql/in_house_apps.go
  • server/datastore/mysql/software_installers.go
  • server/datastore/mysql/vpp.go
  • server/fleet/activities.go
  • server/fleet/datastore.go
  • server/fleet/vpp.go
  • server/mdm/apple/install_application.go
  • server/mdm/apple/vpp/api.go
  • server/mock/datastore_mock.go
  • server/service/activities.go
  • server/service/integration_apple_vpp_config_test.go
  • server/service/integration_mdm_test.go

Comment thread server/datastore/mysql/in_house_apps.go
Comment thread server/datastore/mysql/vpp.go
Comment thread server/service/activities.go

@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

♻️ Duplicate comments (2)
server/datastore/mysql/vpp.go (1)

1412-1437: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Mirror the host existence guard here.

This failure path can insert an orphaned host_vpp_software_installs row when hostID is stale or already deleted. InsertHostVPPSoftwareInstall explicitly checks hosts.id first because this table can't enforce the FK, so this path should do the same to keep success and failure installs consistent.

🤖 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/vpp.go` around lines 1412 - 1437,
RecordFailedVPPAppInstall can insert orphaned host_vpp_software_installs rows
when hostID is stale; mirror the existence guard used in
InsertHostVPPSoftwareInstall by validating the host exists before doing the
INSERT. Inside the same transaction passed to ds.withRetryTxx, query the hosts
table for the given hostID (using the same SELECT used by
InsertHostVPPSoftwareInstall) and return a not-found error if no row exists,
then proceed with the INSERT only after the host check succeeds; keep the check
within the tx so it remains atomic with the insert.
server/service/activities.go (1)

218-223: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don’t hard-code STDQ for seat release.

If the original association used a different pricing tier, this DisassociateAssets request won't match the reserved asset and the cancel path can still leak the seat. Please reuse the asset/pricing metadata from the association path, or look up the asset before disassociating.

🤖 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/service/activities.go` around lines 218 - 223, The
DisassociateAssetsRequest is hard-coding PricingParam="STDQ" which can fail to
match the originally reserved asset and leak seats; update the cancel flow to
reuse the exact pricing metadata from the original association (or fetch the
asset before disassociating) instead of hard-coding STDQ—locate where
DisassociateAssetsRequest is built (vpp.DisassociateAssetsRequest and vpp.Asset
with AdamID/PricingParam) and replace the literal with the stored association's
PricingParam (or call the lookup used in the association path) so the
AdamID+PricingParam pair matches the reservation being released.
🤖 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/vpp.go`:
- Around line 1507-1542: The VPP release-info lookup currently uses
ds.reader(ctx) for both the activated and upcoming queries (activatedStmt and
upcomingStmt) which can miss just-created rows on lagging replicas; update the
lookup in the releaseVPPSeat flow to use the writer connection (ds.writer(ctx))
or execute both queries inside the cancel transaction so they read from the
primary, replacing ds.reader(ctx) with ds.writer(ctx) (or use the transaction's
connection) when calling sqlx.GetContext for activatedStmt and upcomingStmt to
avoid replica-lag NotFound behavior.

---

Duplicate comments:
In `@server/datastore/mysql/vpp.go`:
- Around line 1412-1437: RecordFailedVPPAppInstall can insert orphaned
host_vpp_software_installs rows when hostID is stale; mirror the existence guard
used in InsertHostVPPSoftwareInstall by validating the host exists before doing
the INSERT. Inside the same transaction passed to ds.withRetryTxx, query the
hosts table for the given hostID (using the same SELECT used by
InsertHostVPPSoftwareInstall) and return a not-found error if no row exists,
then proceed with the INSERT only after the host check succeeds; keep the check
within the tx so it remains atomic with the insert.

In `@server/service/activities.go`:
- Around line 218-223: The DisassociateAssetsRequest is hard-coding
PricingParam="STDQ" which can fail to match the originally reserved asset and
leak seats; update the cancel flow to reuse the exact pricing metadata from the
original association (or fetch the asset before disassociating) instead of
hard-coding STDQ—locate where DisassociateAssetsRequest is built
(vpp.DisassociateAssetsRequest and vpp.Asset with AdamID/PricingParam) and
replace the literal with the stored association's PricingParam (or call the
lookup used in the association path) so the AdamID+PricingParam pair matches the
reservation being released.
🪄 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: 6c951c54-d1ef-4c41-9f39-99f47c978fff

📥 Commits

Reviewing files that changed from the base of the PR and between 05b48bf and 77007d3.

📒 Files selected for processing (5)
  • ee/server/service/software_installers.go
  • server/datastore/mysql/vpp.go
  • server/fleet/software_installer.go
  • server/mdm/apple/install_application.go
  • server/service/activities.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • ee/server/service/software_installers.go
  • server/mdm/apple/install_application.go

Comment thread server/datastore/mysql/vpp.go
Comment thread frontend/pages/DashboardPage/cards/ActivityFeed/ActivityFeed.tsx Outdated
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

1 similar comment
@coderabbitai

coderabbitai Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Actionable comments posted: 0

Comment thread ee/server/service/software_installers.go

@RachelElysia RachelElysia left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

FE ✅ thank you!

@jkatz01 jkatz01 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Awesome, thanks for fixing the license leak!

@cdcme
cdcme merged commit c9ae421 into main May 28, 2026
44 checks passed
@cdcme
cdcme deleted the fix-45854-failed-install-activity branch May 28, 2026 18:43
cdcme added a commit that referenced this pull request May 29, 2026
…#46398)

Adds the new `failure_reason` field on the `installed_software` and
`installed_app_store_app` audit-log entries. Code PR: #46332 /
cherry-pick: #46379.
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.

Failed VPP install due to unresolvable variable in managed app configuration emits no activity

4 participants