From 1ca2b951a7d698286b45c8c55ed5fdca3c22339a Mon Sep 17 00:00:00 2001 From: Juan Fernandez Date: Fri, 3 Oct 2025 15:12:53 -0400 Subject: [PATCH] GitOps bug: Icon was ignored when using software URL (#33799) **Related issue:** Resolves #33695 When trying to match package icons, first try to match by hash then by URL. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] QA'd all new/changed functionality manually --------- Co-authored-by: Ian Littman --- server/service/client_software.go | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/server/service/client_software.go b/server/service/client_software.go index 960a3d84d4..739b07d60f 100644 --- a/server/service/client_software.go +++ b/server/service/client_software.go @@ -126,18 +126,33 @@ func (c *Client) applySoftwareInstallers(softwareInstallers []fleet.SoftwareInst // matchPackageIcons hydrates software responses with references to icons in the request payload, so we can track // which API calls to make to add/update/delete icons func matchPackageIcons(request []fleet.SoftwareInstallerPayload, response []fleet.SoftwarePackageResponse) []fleet.SoftwarePackageResponse { - type lookup struct { - Hash string - URL string - } - byLookup := make(map[lookup]fleet.SoftwareInstallerPayload) - for _, clientSide := range request { - byLookup[lookup{Hash: clientSide.SHA256, URL: clientSide.URL}] = clientSide + // On the client side, software installer entries can have a URL or a hash or both ... + byURL := make(map[string]*fleet.SoftwareInstallerPayload) + byHash := make(map[string]*fleet.SoftwareInstallerPayload) + + for i := range request { + clientSide := &request[i] + + if clientSide.URL != "" { + byURL[clientSide.URL] = clientSide + } + if clientSide.SHA256 != "" { + byHash[clientSide.SHA256] = clientSide + } } for i := range response { serverSide := &response[i] - if clientSide, ok := byLookup[lookup{Hash: serverSide.HashSHA256, URL: serverSide.URL}]; ok { + + // All server side entries have a hash, so first try to match by that + if clientSide, ok := byHash[serverSide.HashSHA256]; ok { + serverSide.LocalIconHash = clientSide.IconHash + serverSide.LocalIconPath = clientSide.IconPath + continue + } + + // ... Then by URL + if clientSide, ok := byURL[serverSide.URL]; ok { serverSide.LocalIconHash = clientSide.IconHash serverSide.LocalIconPath = clientSide.IconPath }