VPP: unify List host's software and List my device's software response payload (#20519)

This commit is contained in:
Martin Angers
2024-07-16 16:52:04 -04:00
committed by GitHub
parent 0f9a549ed4
commit 75bdc05f5d
5 changed files with 184 additions and 168 deletions
+35 -23
View File
@@ -3,7 +3,6 @@ package mysql
import (
"context"
"crypto/md5" //nolint:gosec // This hash is used as a DB optimization for software row lookup, not security
"database/sql"
"encoding/hex"
"fmt"
"sort"
@@ -2050,12 +2049,12 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id
st.source,
-- will be NULL for VPP apps for now, self-service not supported yet
si.self_service as self_service,
-- we want that field to be empty string for VPP apps, the filename for installers,
-- and NULL otherwise.
CASE WHEN vap.adam_id IS NOT NULL THEN '' ELSE si.filename END as package_available_for_install,
-- we don't store VPP app information in the package sub-object at the moment,
-- only software installer information
-- this count will be 1 if an installer or VPP app is available, 0 otherwise
IF(COALESCE(si.id, vap.adam_id) IS NOT NULL, 1, 0) as available_for_install,
si.filename as package_name,
si.version as package_version,
vap.adam_id as vpp_app_adam_id,
vap.latest_version as vpp_app_version,
COALESCE(hsi.created_at, hvsi.created_at) as last_install_installed_at,
COALESCE(hsi.execution_id, hvsi.command_uuid) as last_install_install_uuid,
-- get either the softare installer status or the vpp app status
@@ -2070,7 +2069,7 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id
vpp_apps vap ON st.id = vap.title_id
LEFT OUTER JOIN
host_vpp_software_installs hvsi ON vap.adam_id = hvsi.adam_id AND hvsi.host_id = :host_id
LEFT OUTER JOIN
LEFT OUTER JOIN
nano_command_results ncr ON ncr.command_uuid = hvsi.command_uuid
WHERE
-- use the latest install only
@@ -2113,12 +2112,11 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id
st.source,
-- will be NULL for VPP apps for now, self-service not supported yet
si.self_service as self_service,
-- we want that field to be empty string for VPP apps, the filename for installers,
-- and NULL otherwise.
CASE WHEN vap.adam_id IS NOT NULL THEN '' ELSE si.filename END as package_available_for_install,
-- we don't store VPP app information in the package sub-object at the moment,
-- only software installer information
1 as available_for_install,
si.filename as package_name,
si.version as package_version,
vap.adam_id as vpp_app_adam_id,
vap.latest_version as vpp_app_version,
NULL as last_install_installed_at,
NULL as last_install_install_uuid,
NULL as status
@@ -2174,8 +2172,11 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id
name,
source,
self_service,
package_available_for_install,
available_for_install,
package_name,
package_version,
vpp_app_adam_id,
vpp_app_version,
last_install_installed_at,
last_install_install_uuid,
status
@@ -2238,10 +2239,12 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id
type hostSoftware struct {
fleet.HostSoftwareWithInstaller
LastInstallInstalledAt *time.Time `db:"last_install_installed_at"`
LastInstallInstallUUID *string `db:"last_install_install_uuid"`
StatusSort sql.NullInt32 `db:"status_sort"`
PackageVersion *string `db:"package_version"`
LastInstallInstalledAt *time.Time `db:"last_install_installed_at"`
LastInstallInstallUUID *string `db:"last_install_install_uuid"`
PackageName *string `db:"package_name"`
PackageVersion *string `db:"package_version"`
VPPAppAdamID *string `db:"vpp_app_adam_id"`
VPPAppVersion *string `db:"vpp_app_version"`
}
var hostSoftwareList []*hostSoftware
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &hostSoftwareList, stmt, args...); err != nil {
@@ -2264,20 +2267,29 @@ AND EXISTS (SELECT 1 FROM software s JOIN software_cve scve ON scve.software_id
}
// promote the package name and version to the proper destination fields
// (the service layer will arbitrate whether package_available_for_install
// or package fields are returned). For now this "Package" object is only
// for software installers.
if hs.PackageAvailableForInstall != nil && *hs.PackageAvailableForInstall != "" {
if hs.PackageName != nil {
var version string
if hs.PackageVersion != nil {
version = *hs.PackageVersion
}
hs.Package = &fleet.DeviceSoftwarePackage{
Name: *hs.PackageAvailableForInstall,
hs.SoftwarePackage = &fleet.HostSoftwarePackageOrApp{
Name: *hs.PackageName,
Version: version,
}
}
// promote the VPP app id and version to the proper destination fields
if hs.VPPAppAdamID != nil {
var version string
if hs.VPPAppVersion != nil {
version = *hs.VPPAppVersion
}
hs.AppStoreApp = &fleet.HostSoftwarePackageOrApp{
AppStoreID: *hs.VPPAppAdamID,
Version: version,
}
}
titleIDs = append(titleIDs, hs.ID)
byTitleID[hs.ID] = hs
}
+94 -87
View File
@@ -3288,15 +3288,9 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
require.True(t, ok)
require.Equal(t, e.Name, g.Name)
require.Equal(t, e.Source, g.Source)
if e.SelfService != nil {
// there is a software installer, so package information should be present
require.Equal(t, e.SelfService, g.SelfService)
require.NotNil(t, g.Package)
require.NotNil(t, g.PackageAvailableForInstall)
require.Equal(t, e.PackageAvailableForInstall, g.PackageAvailableForInstall)
require.Equal(t, *e.PackageAvailableForInstall, g.Package.Name)
require.NotEmpty(t, g.Package.Version)
}
require.Equal(t, e.AvailableForInstall, g.AvailableForInstall, g.Name+g.Source)
require.Equal(t, e.SoftwarePackage, g.SoftwarePackage)
require.Equal(t, e.AppStoreApp, g.AppStoreApp)
require.Len(t, g.InstalledVersions, len(e.InstalledVersions))
if len(e.InstalledVersions) > 0 {
byVers := make(map[string]fleet.HostSoftwareInstalledVersion, len(e.InstalledVersions))
@@ -3471,33 +3465,36 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
// swi1Pending uses software title id of "b"
expected[byNSV[b].Name+byNSV[b].Source] = fleet.HostSoftwareWithInstaller{
Name: "b",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid1"},
PackageAvailableForInstall: ptr.String("installer-0.pkg"),
SelfService: ptr.Bool(true),
Name: "b",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid1"},
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-0.pkg", Version: "v0.0.0"},
SelfService: ptr.Bool(true),
InstalledVersions: []*fleet.HostSoftwareInstalledVersion{
{Version: byNSV[b].Version, Vulnerabilities: []string{vulns[3].CVE}, InstalledPaths: []string{installPaths[2]}},
},
}
i0 := fleet.HostSoftwareWithInstaller{
Name: "i0",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerInstalled),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid2"},
SelfService: ptr.Bool(true),
PackageAvailableForInstall: ptr.String("installer-1.pkg"),
Name: "i0",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerInstalled),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid2"},
SelfService: ptr.Bool(true),
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-1.pkg", Version: "v1.0.0"},
}
expected[i0.Name+i0.Source] = i0
i1 := fleet.HostSoftwareWithInstaller{
Name: "i1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerFailed),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid3"},
SelfService: ptr.Bool(false),
PackageAvailableForInstall: ptr.String("installer-2.pkg"),
Name: "i1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerFailed),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid3"},
SelfService: ptr.Bool(false),
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-2.pkg", Version: "v2.0.0"},
}
expected[i1.Name+i1.Source] = i1
@@ -3510,22 +3507,24 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
// request with available software
i2 := fleet.HostSoftwareWithInstaller{
Name: "i2",
Source: "apps",
Status: nil,
LastInstall: nil,
PackageAvailableForInstall: ptr.String("installer-3.pkg"),
SelfService: ptr.Bool(false),
Name: "i2",
Source: "apps",
Status: nil,
LastInstall: nil,
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-3.pkg", Version: "v3.0.0"},
SelfService: ptr.Bool(false),
}
expected[i2.Name+i2.Source] = i2
i3 := fleet.HostSoftwareWithInstaller{
Name: "i3",
Source: "apps",
Status: nil,
LastInstall: nil,
PackageAvailableForInstall: ptr.String("installer-4.pkg"),
SelfService: ptr.Bool(false),
Name: "i3",
Source: "apps",
Status: nil,
LastInstall: nil,
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-4.pkg", Version: "v4.0.0"},
SelfService: ptr.Bool(false),
}
expected[i3.Name+i3.Source] = i3
@@ -3569,23 +3568,25 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
})
expected[byNSV[b].Name+byNSV[b].Source] = fleet.HostSoftwareWithInstaller{
Name: "b",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerFailed),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid1"},
PackageAvailableForInstall: ptr.String("installer-0.pkg"),
SelfService: ptr.Bool(true),
Name: "b",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerFailed),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid1"},
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-0.pkg", Version: "v0.0.0"},
SelfService: ptr.Bool(true),
InstalledVersions: []*fleet.HostSoftwareInstalledVersion{
{Version: byNSV[b].Version, Vulnerabilities: []string{vulns[3].CVE}, InstalledPaths: []string{installPaths[2]}},
},
}
expected[i1.Name+i1.Source] = fleet.HostSoftwareWithInstaller{
Name: "i1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid4"},
SelfService: ptr.Bool(false),
PackageAvailableForInstall: ptr.String("installer-2.pkg"),
Name: "i1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: "uuid4"},
SelfService: ptr.Bool(false),
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-2.pkg", Version: "v2.0.0"},
}
// request without available software
@@ -3676,20 +3677,22 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
require.NotEmpty(t, vpp1TmCmdUUID)
expected["vpp1apps"] = fleet.HostSoftwareWithInstaller{
Name: "vpp1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerInstalled),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: vpp1CmdUUID},
SelfService: nil,
PackageAvailableForInstall: ptr.String(""),
Name: "vpp1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerInstalled),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: vpp1CmdUUID},
SelfService: nil,
AvailableForInstall: true,
AppStoreApp: &fleet.HostSoftwarePackageOrApp{AppStoreID: vpp1},
}
expected["vpp2apps"] = fleet.HostSoftwareWithInstaller{
Name: "vpp2",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: vpp2bCmdUUID},
SelfService: nil,
PackageAvailableForInstall: ptr.String(""),
Name: "vpp2",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: vpp2bCmdUUID},
SelfService: nil,
AvailableForInstall: true,
AppStoreApp: &fleet.HostSoftwarePackageOrApp{AppStoreID: vpp2},
}
opts.IncludeAvailableForInstall = false
@@ -3700,12 +3703,13 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
compareResults(expected, sw, true, i3.Name+i3.Source, i2.Name+i2.Source) // i3 is for team, i2 is available (excluded)
expected["vpp3apps"] = fleet.HostSoftwareWithInstaller{
Name: "vpp3",
Source: "apps",
Status: nil,
LastInstall: nil,
SelfService: nil,
PackageAvailableForInstall: ptr.String(""),
Name: "vpp3",
Source: "apps",
Status: nil,
LastInstall: nil,
SelfService: nil,
AvailableForInstall: true,
AppStoreApp: &fleet.HostSoftwarePackageOrApp{AppStoreID: vpp3},
}
opts.IncludeAvailableForInstall = true
opts.ListOptions.PerPage = 20
@@ -3722,12 +3726,13 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
compareResults(map[string]fleet.HostSoftwareWithInstaller{
i3.Name + i3.Source: expected[i3.Name+i3.Source],
"vpp1apps": {
Name: "vpp1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: vpp1TmCmdUUID},
SelfService: nil,
PackageAvailableForInstall: ptr.String(""),
Name: "vpp1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: vpp1TmCmdUUID},
SelfService: nil,
AvailableForInstall: true,
AppStoreApp: &fleet.HostSoftwarePackageOrApp{AppStoreID: vpp1},
},
}, sw, true)
@@ -3745,20 +3750,22 @@ func testListHostSoftware(t *testing.T, ds *Datastore) {
{Version: otherSoftware[1].Version},
}},
"i1apps": {
Name: "i1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: otherHostI1UUID},
SelfService: ptr.Bool(false),
PackageAvailableForInstall: ptr.String("installer-2.pkg"),
Name: "i1",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: otherHostI1UUID},
SelfService: ptr.Bool(false),
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-2.pkg", Version: "v2.0.0"},
},
"i2apps": {
Name: "i2",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: otherHostI2UUID},
SelfService: ptr.Bool(false),
PackageAvailableForInstall: ptr.String("installer-3.pkg"),
Name: "i2",
Source: "apps",
Status: expectStatus(fleet.SoftwareInstallerPending),
LastInstall: &fleet.HostSoftwareInstall{InstallUUID: otherHostI2UUID},
SelfService: ptr.Bool(false),
AvailableForInstall: true,
SoftwarePackage: &fleet.HostSoftwarePackageOrApp{Name: "installer-3.pkg", Version: "v3.0.0"},
},
}
compareResults(expectedOther, sw, true)
+17 -14
View File
@@ -315,23 +315,26 @@ type HostSoftwareWithInstaller struct {
LastInstall *HostSoftwareInstall `json:"last_install"`
InstalledVersions []*HostSoftwareInstalledVersion `json:"installed_versions"`
// PackageAvailableForInstall is only present for the user-authenticated
// endpoint, not the device-authenticated one. If non-nil and non-empty, it
// indicates that a software installer is present for that software (and the
// name is the installer's filename). If non-nil and empty, it indicates that
// a VPP app is present for that software. If nil, none of those are present.
PackageAvailableForInstall *string `json:"package_available_for_install,omitempty" db:"package_available_for_install"`
// AvailableForInstall is true if a software installer or a VPP app is
// available to install this software.
AvailableForInstall bool `json:"available_for_install" db:"available_for_install"`
// Package provides software installer package information, it is only
// present for the device-authenticated endpoint, not for the
// user-authenticated one.
Package *DeviceSoftwarePackage `json:"package,omitempty"`
// SoftwarePackage provides software installer package information, it is
// only present if a software installer is available for the software title.
SoftwarePackage *HostSoftwarePackageOrApp `json:"software_package"`
// AppStoreApp provides VPP app information, it is only present if a VPP app
// is available for the software title.
AppStoreApp *HostSoftwarePackageOrApp `json:"app_store_app"`
}
// DeviceSoftwarePackage provides information about a software installer
// package for self-service on a device.
type DeviceSoftwarePackage struct {
Name string `json:"name"`
// HostSoftwarePackageOrApp provides information about a software installer
// package or a VPP app.
type HostSoftwarePackageOrApp struct {
// AppStoreID is only present for VPP apps.
AppStoreID string `json:"app_store_id,omitempty"`
// Name is only present for software installer packages.
Name string `json:"name,omitempty"`
Version string `json:"version"`
}
-13
View File
@@ -2563,18 +2563,5 @@ func (svc *Service) ListHostSoftware(ctx context.Context, hostID uint, opts flee
opts.IncludeAvailableForInstall = includeAvailableForInstall || opts.SelfServiceOnly
software, meta, err := svc.ds.ListHostSoftware(ctx, host, opts)
if includeAvailableForInstall {
// for the host software page, we don't want to return the package object,
// only the package name
for _, s := range software {
s.Package = nil
}
} else {
// for the device page, we don't want to return the package name, only the
// package object
for _, s := range software {
s.PackageAvailableForInstall = nil
}
}
return software, meta, ctxerr.Wrap(ctx, err, "list host software")
}
+38 -31
View File
@@ -9148,11 +9148,13 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.Len(t, getHostSw.Software[1].InstalledVersions, 2)
// no package information as there is no installer
require.Nil(t, getHostSw.Software[0].SelfService)
require.Nil(t, getHostSw.Software[0].Package)
require.Nil(t, getHostSw.Software[0].PackageAvailableForInstall)
require.False(t, getHostSw.Software[0].AvailableForInstall)
require.Nil(t, getHostSw.Software[0].SoftwarePackage)
require.Nil(t, getHostSw.Software[0].AppStoreApp)
require.Nil(t, getHostSw.Software[1].SelfService)
require.Nil(t, getHostSw.Software[1].Package)
require.Nil(t, getHostSw.Software[1].PackageAvailableForInstall)
require.False(t, getHostSw.Software[1].AvailableForInstall)
require.Nil(t, getHostSw.Software[1].SoftwarePackage)
require.Nil(t, getHostSw.Software[1].AppStoreApp)
// Add vulnerabilities to software to check query param filtering
_, err = s.ds.InsertSoftwareVulnerability(ctx, fleet.SoftwareVulnerability{SoftwareID: barSoftwareID, CVE: "CVE-bar-1234"}, fleet.NVDSource)
@@ -9166,8 +9168,9 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.NoError(t, err)
require.Equal(t, "bar", getHostSw.Software[0].Name)
require.Nil(t, getHostSw.Software[0].SelfService)
require.Nil(t, getHostSw.Software[0].Package)
require.Nil(t, getHostSw.Software[0].PackageAvailableForInstall)
require.False(t, getHostSw.Software[0].AvailableForInstall)
require.Nil(t, getHostSw.Software[0].SoftwarePackage)
require.Nil(t, getHostSw.Software[0].AppStoreApp)
require.Len(t, getHostSw.Software[0].InstalledVersions, 1)
require.Len(t, getHostSw.Software[0].InstalledVersions[0].Vulnerabilities, 2)
require.Equal(t, getHostSw.Software[0].InstalledVersions[0].Vulnerabilities, []string{"CVE-bar-1234", "CVE-bar-5678"})
@@ -9182,11 +9185,13 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.Len(t, getDeviceSw.Software[1].InstalledVersions, 2)
// no package information as there is no installer
require.Nil(t, getDeviceSw.Software[0].SelfService)
require.Nil(t, getDeviceSw.Software[0].Package)
require.Nil(t, getDeviceSw.Software[0].PackageAvailableForInstall)
require.False(t, getDeviceSw.Software[0].AvailableForInstall)
require.Nil(t, getDeviceSw.Software[0].SoftwarePackage)
require.Nil(t, getDeviceSw.Software[0].AppStoreApp)
require.Nil(t, getDeviceSw.Software[1].SelfService)
require.Nil(t, getDeviceSw.Software[1].Package)
require.Nil(t, getDeviceSw.Software[1].PackageAvailableForInstall)
require.False(t, getDeviceSw.Software[1].AvailableForInstall)
require.Nil(t, getDeviceSw.Software[1].SoftwarePackage)
require.Nil(t, getDeviceSw.Software[1].AppStoreApp)
// create a software installer, not installed on the host
payload := &fleet.UploadSoftwareInstallerPayload{
@@ -9208,18 +9213,19 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/hosts/%d/software", host.ID), nil, http.StatusOK, &getHostSw)
require.Len(t, getHostSw.Software, 3) // foo, bar and ruby.deb
require.Equal(t, getHostSw.Software[0].Name, "bar")
require.Nil(t, getHostSw.Software[0].PackageAvailableForInstall)
require.False(t, getHostSw.Software[0].AvailableForInstall)
require.Equal(t, getHostSw.Software[1].Name, "foo")
require.Nil(t, getHostSw.Software[1].PackageAvailableForInstall)
require.False(t, getHostSw.Software[1].AvailableForInstall)
require.Equal(t, getHostSw.Software[2].Name, "ruby")
require.Len(t, getHostSw.Software[1].InstalledVersions, 2)
require.NotNil(t, getHostSw.Software[2].PackageAvailableForInstall)
require.Equal(t, "ruby.deb", *getHostSw.Software[2].PackageAvailableForInstall)
require.True(t, getHostSw.Software[2].AvailableForInstall)
require.Nil(t, getHostSw.Software[2].AppStoreApp)
require.NotNil(t, getHostSw.Software[2].SoftwarePackage)
require.Equal(t, "ruby.deb", getHostSw.Software[2].SoftwarePackage.Name)
require.Equal(t, payload.Version, getHostSw.Software[2].SoftwarePackage.Version)
require.NotNil(t, getHostSw.Software[2].SelfService)
require.True(t, *getHostSw.Software[2].SelfService)
require.Nil(t, getHostSw.Software[2].Status)
// package object is not returned for user-authenticated endpoint
require.Nil(t, getHostSw.Software[2].Package)
// only the installer is returned for self-service only
getHostSw = getHostSoftwareResponse{}
@@ -9236,8 +9242,8 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.Equal(t, getDeviceSw.Software[0].Name, "bar")
require.Equal(t, getDeviceSw.Software[1].Name, "foo")
require.Len(t, getDeviceSw.Software[1].InstalledVersions, 2)
require.Nil(t, getDeviceSw.Software[0].PackageAvailableForInstall)
require.Nil(t, getDeviceSw.Software[1].PackageAvailableForInstall)
require.False(t, getDeviceSw.Software[0].AvailableForInstall)
require.False(t, getDeviceSw.Software[1].AvailableForInstall)
// but it gets returned for self-service only
res = s.DoRawNoAuth("GET", "/api/latest/fleet/device/"+token+"/software?self_service=1", nil, http.StatusOK)
@@ -9246,14 +9252,13 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.NoError(t, err)
require.Len(t, getDeviceSw.Software, 1)
require.Equal(t, getDeviceSw.Software[0].Name, "ruby")
// package available for install is not returned for device-authenticated
require.Nil(t, getDeviceSw.Software[0].PackageAvailableForInstall)
// but package object is
require.NotNil(t, getDeviceSw.Software[0].Package)
require.True(t, getDeviceSw.Software[0].AvailableForInstall)
require.Nil(t, getDeviceSw.Software[0].AppStoreApp)
require.NotNil(t, getDeviceSw.Software[0].SoftwarePackage)
require.NotNil(t, getDeviceSw.Software[0].SelfService)
require.True(t, *getDeviceSw.Software[0].SelfService)
require.Equal(t, payload.Filename, getDeviceSw.Software[0].Package.Name)
require.Equal(t, payload.Version, getDeviceSw.Software[0].Package.Version)
require.Equal(t, payload.Filename, getDeviceSw.Software[0].SoftwarePackage.Name)
require.Equal(t, payload.Version, getDeviceSw.Software[0].SoftwarePackage.Version)
// request installation on the host
var installResp installSoftwareResponse
@@ -9268,13 +9273,13 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.Equal(t, getHostSw.Software[1].Name, "foo")
require.Equal(t, getHostSw.Software[2].Name, "ruby")
require.Len(t, getHostSw.Software[1].InstalledVersions, 2)
require.NotNil(t, getHostSw.Software[2].PackageAvailableForInstall)
require.Equal(t, "ruby.deb", *getHostSw.Software[2].PackageAvailableForInstall)
require.True(t, getHostSw.Software[2].AvailableForInstall)
require.NotNil(t, getHostSw.Software[2].SoftwarePackage)
require.Equal(t, "ruby.deb", getHostSw.Software[2].SoftwarePackage.Name)
require.NotNil(t, getHostSw.Software[2].Status)
require.Equal(t, fleet.SoftwareInstallerPending, *getHostSw.Software[2].Status)
require.NotNil(t, getHostSw.Software[2].SelfService)
require.True(t, *getHostSw.Software[2].SelfService)
require.Nil(t, getHostSw.Software[2].Package)
// still returned with self-service filter
getHostSw = getHostSoftwareResponse{}
@@ -9292,12 +9297,13 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.Equal(t, getDeviceSw.Software[1].Name, "foo")
require.Equal(t, getDeviceSw.Software[2].Name, "ruby")
require.Len(t, getDeviceSw.Software[1].InstalledVersions, 2)
require.Nil(t, getDeviceSw.Software[2].PackageAvailableForInstall)
require.True(t, getDeviceSw.Software[2].AvailableForInstall)
require.NotNil(t, getDeviceSw.Software[2].Status)
require.Equal(t, fleet.SoftwareInstallerPending, *getDeviceSw.Software[2].Status)
require.NotNil(t, getDeviceSw.Software[2].SelfService)
require.True(t, *getDeviceSw.Software[2].SelfService)
require.NotNil(t, getDeviceSw.Software[2].Package)
require.NotNil(t, getDeviceSw.Software[2].SoftwarePackage)
require.Nil(t, getDeviceSw.Software[2].AppStoreApp)
// still returned for self-service only too
res = s.DoRawNoAuth("GET", "/api/latest/fleet/device/"+token+"/software?self_service=1", nil, http.StatusOK)
@@ -9308,8 +9314,9 @@ func (s *integrationEnterpriseTestSuite) TestListHostSoftware() {
require.Equal(t, getDeviceSw.Software[0].Name, "ruby")
require.NotNil(t, getDeviceSw.Software[0].SelfService)
require.True(t, *getDeviceSw.Software[0].SelfService)
require.NotNil(t, getDeviceSw.Software[0].Package)
require.Nil(t, getDeviceSw.Software[0].PackageAvailableForInstall)
require.NotNil(t, getDeviceSw.Software[0].SoftwarePackage)
require.Nil(t, getDeviceSw.Software[0].AppStoreApp)
require.True(t, getDeviceSw.Software[0].AvailableForInstall)
// test with a query
getHostSw = getHostSoftwareResponse{}