Multiple packages: install-time precedence and setup experience - #48708
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## feat/28108-multiple-custom-packages #48708 +/- ##
======================================================================
Coverage ? 68.04%
======================================================================
Files ? 3680
Lines ? 234292
Branches ? 12454
======================================================================
Hits ? 159427
Misses ? 60512
Partials ? 14353
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@claude review once. |
There was a problem hiding this comment.
Not approving auto — this touches install precedence, setup experience queuing, policy automation, and multi-package software display across service and datastore layers with new SQL (CTEs, window functions, subquery MIN() collapses), and it changes API surface (new software_installer_id field). Bug hunter found no issues, but the scope + criticality warrants a human eye.
Extended reasoning...
Overview
The PR implements the runtime side of Fleet's multi-package feature on top of the feat/28108-multiple-custom-packages branch. Roughly four behavior changes:
- Install precedence (
ee/server/service/software_installers.go): NewresolveFirstAddedInScopeInstallerpicks the first-added (smallest installer_id) in-scope, platform-compatible package. RewiresInstallSoftwareTitleandSelfServiceInstallSoftwareTitleto use it. Preserves the two distinct error messages (not-in-scope vs not-self-service). - Setup experience (
server/datastore/mysql/setup_experience.go): AddsROW_NUMBER() OVER (PARTITION BY software_title_id ...)around the combined installer/VPP UNION so a multi-package title queues only its first-added package. - Policy automation (
server/datastore/mysql/policies.go,server/service/team_policies.go,server/fleet/*policies.go): GitOpsApplyPolicySpecsnowORDER BY si_id IS NULL, si_id ASC LIMIT 1to pin to the first-added package. Adds a newsoftware_installer_idfield onTeamPolicyRequest/ModifyPolicyPayloadto override the default.DeleteSoftwareInstallerre-points policies to the first-added surviving package before deleting, or lets the FK 409 fire when there is no survivor. - Host software listing (
server/datastore/mysql/software.go):filterSoftwareInstallersByLabelreturns a resolved package map instead of a filter; a newresolveFirstAddedInstallersForHostruns the four label-scope CTEs across every active package of the titles.ListHostSoftwarepins the display join to those resolved installer IDs, andhostSoftwareInstalls/hostSoftwareUninstallsaddMIN(id)subqueries to collapse historical rows.
Security risks
No authn/authz code changes. The user-facing surface additions (software_installer_id on policy create/modify) route through the existing authz.ActionWrite check on policies, and the new field is validated against GetSoftwarePackagesByTeamAndTitleID for the same team, which rejects cross-team installer IDs with a 400. The new SQL uses sqlx.Named+sqlx.In with parameterized args (no interpolation), so no injection surface.
Level of scrutiny
High. This is production-critical multi-tenant code: (a) install execution path (chooses which package to install on a host), (b) policy automation on failure (which package a failing policy triggers), (c) setup experience queuing (what runs on new-host bootstrap), (d) inventory display for tens of thousands of hosts. A precedence bug here can queue the wrong package for enrollments-in-flight or leak availability across labels. The four candidate tiers (both/inScopeAny/compatAny/any) in resolveFirstAddedInstallersForHost are new and subtle — the fallback-any tier means a title is never hidden but the installed package can be non-compatible on the display side. Worth a human verifying that matches product intent.
Other factors
- Base branch is
feat/28108-multiple-custom-packages, notmain. This is a first-pass PR onto a feature branch, and the merge intomainwill presumably be reviewed again downstream — but this PR still lands on that feature branch and merits scrutiny now. - Test coverage is decent (integration tests for install precedence, policy default/override/reject, delete re-point; datastore tests for first-added policy resolution, setup-experience dedupe, list-host-software display). Codecov flags ~35 uncovered lines, mostly in fallback branches of the resolver and the modify-policy validation.
- PR title says "first pass" — the author signals more iteration to come.
- No prior human reviews on the timeline other than the request-for-review comment.
There was a problem hiding this comment.
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.
a5c85af
into
feat/28108-multiple-custom-packages
**Related issue:** Resolves #28108 Adds support for uploading multiple custom packages (up to 10) for the same software title on a team — so IT admins can deploy different versions or architectures (for example, Arm vs. Intel builds or staged rollouts) to label-scoped hosts instead of splitting them across teams. The software title keeps a single first-added `software_package` for backwards compatibility, and first-added-wins resolves overlaps consistently across self-service, manual install, policy automation, and setup experience. Feature branch combining the sub-PRs: migration (#48596), packages[] API and add/edit/delete-package endpoints (#48607), install-time precedence and setup experience (#48708), GitOps (#48710), Library and Add/Edit/Delete modals (#48520), secondary UI — policy automation, setup experience, and install-details hash (#49079), and the host install-result `hash_sha256` field (#49085). # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. - [x] 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 - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually ## Database migrations - [x] Checked schema for all modified table for columns that will auto-update timestamps during migration. - [x] Confirmed that updating the timestamps is acceptable, and will not cause unwanted side effects. - [x] Ensured the correct collation is explicitly set for character columns (`COLLATE utf8mb4_unicode_ci`). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Support up to 10 custom packages per software title, with package-scoped deploy/install settings and package-specific edit/delete. * Policy automation can pin “Install software” to a specific package. * GitOps generation now outputs repeatable multi-package YAML per title. * Software install details now display the package SHA-256 hash (when available) with a copy-to-clipboard action. * **Bug Fixes** * Improved deterministic “first-added” precedence for installs, listings, setup experience, and policy dispatch when multiple packages match. * Fixed installer targeting and per-package metadata persistence (including installer-specific activity details). * **Accessibility/UX** * Added optional `aria-label` support for dropdowns. * Info banners can now render a leading icon with configurable color. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
Related issue: Resolves #48398
Applies first-added-wins install precedence everywhere a host can match more than one package of a software title: manual install, self-service, policy auto-install, setup experience, and the host-software read all resolve the first-added package the host is in label scope for. Policy automations can now target a specific package (defaulting to first-added), and deleting a package re-points its automations to the first-added surviving package.
Checklist for submitter
SELECT *is avoided, SQL injection is prevented (using placeholders for values in statements).Testing