|
|
|
@@ -28,6 +28,7 @@ func TestSoftwareTitles(t *testing.T) {
|
|
|
|
|
{"TeamFilterSoftwareTitles", testTeamFilterSoftwareTitles},
|
|
|
|
|
{"ListSoftwareTitlesInstallersOnly", testListSoftwareTitlesInstallersOnly},
|
|
|
|
|
{"ListSoftwareTitlesAvailableForInstallFilter", testListSoftwareTitlesAvailableForInstallFilter},
|
|
|
|
|
{"ListSoftwareTitlesAllTeams", testListSoftwareTitlesAllTeams},
|
|
|
|
|
{"UploadedSoftwareExists", testUploadedSoftwareExists},
|
|
|
|
|
}
|
|
|
|
|
for _, c := range cases {
|
|
|
|
@@ -259,6 +260,10 @@ func testSoftwareSyncHostsSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
//
|
|
|
|
|
// All tests below are in hosts in "No team".
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
host1 := test.NewHost(t, ds, "host1", "", "host1key", "host1uuid", time.Now())
|
|
|
|
@@ -316,8 +321,10 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
_, err = ds.InsertSoftwareInstallRequest(ctx, host1.ID, installer2, false)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
// create a VPP app not installed anywhere
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp1", BundleIdentifier: "com.app.vpp1",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.IPadOSPlatform}}, nil)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp1", BundleIdentifier: "com.app.vpp1",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.IPadOSPlatform},
|
|
|
|
|
}, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftware(ctx, time.Now()))
|
|
|
|
@@ -325,10 +332,13 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftwareTitles(ctx, time.Now()))
|
|
|
|
|
|
|
|
|
|
// primary sort is "hosts_count DESC", followed by "name ASC, source ASC, browser ASC"
|
|
|
|
|
titles, _, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "hosts_count",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "hosts_count",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 10)
|
|
|
|
|
i := 0
|
|
|
|
@@ -385,10 +395,13 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.NotNil(t, titles[i].AppStoreApp)
|
|
|
|
|
|
|
|
|
|
// primary sort is "hosts_count ASC", followed by "name ASC, source ASC, browser ASC"
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "hosts_count",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "hosts_count",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 10)
|
|
|
|
|
i = 0
|
|
|
|
@@ -425,10 +438,13 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.Equal(t, "deb_packages", titles[i].Source)
|
|
|
|
|
|
|
|
|
|
// primary sort is "name ASC", followed by "host_count DESC, source ASC, browser ASC"
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 10)
|
|
|
|
|
i = 0
|
|
|
|
@@ -465,10 +481,13 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
assert.Equal(t, "ipados_apps", titles[i].Source)
|
|
|
|
|
|
|
|
|
|
// primary sort is "name DESC", followed by "host_count DESC, source ASC, browser ASC"
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 10)
|
|
|
|
|
i = 0
|
|
|
|
@@ -505,11 +524,14 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.Equal(t, "apps", titles[i].Source)
|
|
|
|
|
|
|
|
|
|
// using a match query
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
MatchQuery: "ba",
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
MatchQuery: "ba",
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 4)
|
|
|
|
|
require.Equal(t, "baz", titles[0].Name)
|
|
|
|
@@ -524,11 +546,14 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.Equal(t, "apps", titles[3].Source)
|
|
|
|
|
|
|
|
|
|
// using another (installer-only) match query
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
MatchQuery: "insta",
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
MatchQuery: "insta",
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 2)
|
|
|
|
|
require.Equal(t, "installer2", titles[0].Name)
|
|
|
|
@@ -537,10 +562,14 @@ func testOrderSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.Equal(t, "apps", titles[1].Source)
|
|
|
|
|
|
|
|
|
|
// filter on self-service only
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
}, SelfServiceOnly: true}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, _, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderDescending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
SelfServiceOnly: true,
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 1)
|
|
|
|
|
require.Equal(t, "installer1", titles[0].Name)
|
|
|
|
@@ -615,32 +644,39 @@ func testTeamFilterSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotZero(t, installer2)
|
|
|
|
|
|
|
|
|
|
// create a VPP app for team2
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp2", BundleIdentifier: "com.app.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.IOSPlatform}}, &team2.ID)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp2", BundleIdentifier: "com.app.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.IOSPlatform},
|
|
|
|
|
}, &team2.ID)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// create a VPP app for No Team
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp3", BundleIdentifier: "com.app.vpp3",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_3", Platform: fleet.MacOSPlatform}}, ptr.Uint(0))
|
|
|
|
|
// create a VPP app for "No team"
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp3", BundleIdentifier: "com.app.vpp3",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_3", Platform: fleet.MacOSPlatform},
|
|
|
|
|
}, ptr.Uint(0))
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftware(ctx, time.Now()))
|
|
|
|
|
require.NoError(t, ds.ReconcileSoftwareTitles(ctx))
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftwareTitles(ctx, time.Now()))
|
|
|
|
|
|
|
|
|
|
// Testing the global user (for no team)
|
|
|
|
|
// Testing the global user (for "All teams")
|
|
|
|
|
// Should not return VPP apps or software installers (because they are not installed yet).
|
|
|
|
|
globalTeamFilter := fleet.TeamFilter{User: userGlobalAdmin, IncludeObserver: true}
|
|
|
|
|
titles, count, _, err := ds.ListSoftwareTitles(
|
|
|
|
|
context.Background(), fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{}}, globalTeamFilter,
|
|
|
|
|
context.Background(), fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{},
|
|
|
|
|
TeamID: nil,
|
|
|
|
|
}, globalTeamFilter,
|
|
|
|
|
)
|
|
|
|
|
sortTitlesByName(titles)
|
|
|
|
|
// software installers are associated with a team, so they don't show up in
|
|
|
|
|
// this request for no team, but other titles do because software titles are
|
|
|
|
|
// not associated with a team.
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 3)
|
|
|
|
|
require.Equal(t, 3, count)
|
|
|
|
|
require.Len(t, titles, 2)
|
|
|
|
|
require.Equal(t, 2, count)
|
|
|
|
|
|
|
|
|
|
require.Equal(t, "bar", titles[0].Name)
|
|
|
|
|
require.Equal(t, "deb_packages", titles[0].Source)
|
|
|
|
|
require.Equal(t, "foo", titles[1].Name)
|
|
|
|
@@ -653,19 +689,36 @@ func testTeamFilterSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
assert.Equal(t, uint(2), titles[1].HostsCount)
|
|
|
|
|
require.Nil(t, titles[1].SoftwarePackage)
|
|
|
|
|
require.Nil(t, titles[1].AppStoreApp)
|
|
|
|
|
require.Equal(t, uint(0), titles[2].VersionsCount)
|
|
|
|
|
require.Nil(t, titles[2].SoftwarePackage)
|
|
|
|
|
require.Equal(t, "vpp3", titles[2].Name)
|
|
|
|
|
barTitle := titles[0]
|
|
|
|
|
fooTitle := titles[1]
|
|
|
|
|
|
|
|
|
|
title, err := ds.SoftwareTitleByID(context.Background(), titles[0].ID, nil, globalTeamFilter)
|
|
|
|
|
// Testing the global user (for "No team")
|
|
|
|
|
// should only return vpp3 because it's the only app in the "No team".
|
|
|
|
|
titles, count, _, err = ds.ListSoftwareTitles(
|
|
|
|
|
context.Background(), fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, globalTeamFilter,
|
|
|
|
|
)
|
|
|
|
|
sortTitlesByName(titles)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Len(t, titles, 1)
|
|
|
|
|
require.Equal(t, 1, count)
|
|
|
|
|
require.Equal(t, uint(0), titles[0].VersionsCount)
|
|
|
|
|
require.Nil(t, titles[0].SoftwarePackage)
|
|
|
|
|
require.Equal(t, "vpp3", titles[0].Name)
|
|
|
|
|
|
|
|
|
|
// Get title of bar software.
|
|
|
|
|
title, err := ds.SoftwareTitleByID(context.Background(), barTitle.ID, nil, globalTeamFilter)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Zero(t, title.SoftwareInstallersCount)
|
|
|
|
|
require.Zero(t, title.VPPAppsCount)
|
|
|
|
|
|
|
|
|
|
// ListSoftwareTitles does not populate version host counts, so we do that manually
|
|
|
|
|
titles[0].Versions[0].HostsCount = ptr.Uint(1)
|
|
|
|
|
barTitle.Versions[0].HostsCount = ptr.Uint(1)
|
|
|
|
|
assert.Equal(
|
|
|
|
|
t,
|
|
|
|
|
titles[0],
|
|
|
|
|
barTitle,
|
|
|
|
|
fleet.SoftwareTitleListResult{
|
|
|
|
|
ID: title.ID,
|
|
|
|
|
Name: title.Name,
|
|
|
|
@@ -679,11 +732,11 @@ func testTeamFilterSoftwareTitles(t *testing.T, ds *Datastore) {
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Testing with team filter -- this team does not contain this software title
|
|
|
|
|
_, err = ds.SoftwareTitleByID(context.Background(), titles[0].ID, &team1.ID, globalTeamFilter)
|
|
|
|
|
_, err = ds.SoftwareTitleByID(context.Background(), barTitle.ID, &team1.ID, globalTeamFilter)
|
|
|
|
|
assert.ErrorIs(t, err, sql.ErrNoRows)
|
|
|
|
|
|
|
|
|
|
// Testing with team filter -- this team does contain this software title
|
|
|
|
|
title, err = ds.SoftwareTitleByID(context.Background(), titles[1].ID, &team1.ID, globalTeamFilter)
|
|
|
|
|
title, err = ds.SoftwareTitleByID(context.Background(), fooTitle.ID, &team1.ID, globalTeamFilter)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.Zero(t, title.SoftwareInstallersCount)
|
|
|
|
|
require.Zero(t, title.VPPAppsCount)
|
|
|
|
@@ -808,14 +861,19 @@ func testListSoftwareTitlesInstallersOnly(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.NotZero(t, installer2)
|
|
|
|
|
// create a VPP app not installed on a host
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp1", BundleIdentifier: "com.app,vpp1",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.MacOSPlatform}}, nil)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp1", BundleIdentifier: "com.app,vpp1",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.MacOSPlatform},
|
|
|
|
|
}, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
titles, counts, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, counts, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.EqualValues(t, 3, counts)
|
|
|
|
|
require.Len(t, titles, 3)
|
|
|
|
@@ -834,11 +892,14 @@ func testListSoftwareTitlesInstallersOnly(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftwareTitles(ctx, time.Now()))
|
|
|
|
|
|
|
|
|
|
// match installer1 name
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
MatchQuery: "installer1",
|
|
|
|
|
}}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
MatchQuery: "installer1",
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.EqualValues(t, 1, counts)
|
|
|
|
|
require.Len(t, titles, 1)
|
|
|
|
@@ -847,11 +908,15 @@ func testListSoftwareTitlesInstallersOnly(t *testing.T, ds *Datastore) {
|
|
|
|
|
require.True(t, titles[0].CountsUpdatedAt.IsZero())
|
|
|
|
|
|
|
|
|
|
// vulnerable only returns nothing
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
MatchQuery: "installer1",
|
|
|
|
|
}, VulnerableOnly: true}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
MatchQuery: "installer1",
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
VulnerableOnly: true,
|
|
|
|
|
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.EqualValues(t, 0, counts)
|
|
|
|
|
require.Len(t, titles, 0)
|
|
|
|
@@ -865,6 +930,7 @@ func testListSoftwareTitlesInstallersOnly(t *testing.T, ds *Datastore) {
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
AvailableForInstall: true,
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
@@ -877,7 +943,7 @@ func testListSoftwareTitlesInstallersOnly(t *testing.T, ds *Datastore) {
|
|
|
|
|
func testListSoftwareTitlesAvailableForInstallFilter(t *testing.T, ds *Datastore) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
// create a 2 software installers
|
|
|
|
|
// create 2 software installers
|
|
|
|
|
installer1, err := ds.MatchOrCreateSoftwareInstaller(ctx, &fleet.UploadSoftwareInstallerPayload{
|
|
|
|
|
Title: "installer1",
|
|
|
|
|
Source: "apps",
|
|
|
|
@@ -896,17 +962,25 @@ func testListSoftwareTitlesAvailableForInstallFilter(t *testing.T, ds *Datastore
|
|
|
|
|
require.NotZero(t, installer2)
|
|
|
|
|
|
|
|
|
|
// create a 4 VPP apps
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp1", BundleIdentifier: "com.example.vpp1",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.MacOSPlatform}}, nil)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp1", BundleIdentifier: "com.example.vpp1",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_1", Platform: fleet.MacOSPlatform},
|
|
|
|
|
}, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp2", BundleIdentifier: "com.example.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.IPadOSPlatform}}, nil)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp2", BundleIdentifier: "com.example.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.IPadOSPlatform},
|
|
|
|
|
}, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp2", BundleIdentifier: "com.example.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.MacOSPlatform}}, nil)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp2", BundleIdentifier: "com.example.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.MacOSPlatform},
|
|
|
|
|
}, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{Name: "vpp2", BundleIdentifier: "com.example.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.IOSPlatform}}, nil)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "vpp2", BundleIdentifier: "com.example.vpp2",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_2", Platform: fleet.IOSPlatform},
|
|
|
|
|
}, nil)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
host := test.NewHost(t, ds, "host", "", "hostkey", "hostuuid", time.Now())
|
|
|
|
@@ -929,6 +1003,7 @@ func testListSoftwareTitlesAvailableForInstallFilter(t *testing.T, ds *Datastore
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
@@ -963,6 +1038,7 @@ func testListSoftwareTitlesAvailableForInstallFilter(t *testing.T, ds *Datastore
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
AvailableForInstall: true,
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
@@ -984,6 +1060,191 @@ func testListSoftwareTitlesAvailableForInstallFilter(t *testing.T, ds *Datastore
|
|
|
|
|
}, names)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testListSoftwareTitlesAllTeams(t *testing.T, ds *Datastore) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|
team1, err := ds.NewTeam(ctx, &fleet.Team{Name: "team1"})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
team2, err := ds.NewTeam(ctx, &fleet.Team{Name: "team2"})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Create a macOS software foobar installer on "No team".
|
|
|
|
|
macOSInstallerNoTeam, err := ds.MatchOrCreateSoftwareInstaller(ctx, &fleet.UploadSoftwareInstallerPayload{
|
|
|
|
|
Title: "foobar",
|
|
|
|
|
BundleIdentifier: "com.foo.bar",
|
|
|
|
|
Source: "apps",
|
|
|
|
|
InstallScript: "echo",
|
|
|
|
|
Filename: "foobar.pkg",
|
|
|
|
|
TeamID: nil,
|
|
|
|
|
})
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Create an iOS Canva installer on "team1".
|
|
|
|
|
require.NotZero(t, macOSInstallerNoTeam)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "Canva", BundleIdentifier: "com.example.canva",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_canva", Platform: fleet.IOSPlatform},
|
|
|
|
|
}, &team1.ID)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Create a macOS Canva installer on "team1".
|
|
|
|
|
require.NotZero(t, macOSInstallerNoTeam)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "Canva", BundleIdentifier: "com.example.canva",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_canva", Platform: fleet.MacOSPlatform},
|
|
|
|
|
}, &team1.ID)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Create an iPadOS Canva installer on "team2".
|
|
|
|
|
require.NotZero(t, macOSInstallerNoTeam)
|
|
|
|
|
_, err = ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{
|
|
|
|
|
Name: "Canva", BundleIdentifier: "com.example.canva",
|
|
|
|
|
VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_app_canva", Platform: fleet.IPadOSPlatform},
|
|
|
|
|
}, &team2.ID)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Add a macOS host on "No team" with some software.
|
|
|
|
|
host := test.NewHost(t, ds, "host", "", "hostkey", "hostuuid", time.Now())
|
|
|
|
|
software := []fleet.Software{
|
|
|
|
|
{Name: "foo", Version: "0.0.1", Source: "chrome_extensions"},
|
|
|
|
|
{Name: "foo", Version: "0.0.3", Source: "chrome_extensions"},
|
|
|
|
|
{Name: "bar", Version: "0.0.3", Source: "deb_packages"},
|
|
|
|
|
}
|
|
|
|
|
_, err = ds.UpdateHostSoftware(ctx, host.ID, software)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
// Simulate vulnerabilities cron
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftware(ctx, time.Now()))
|
|
|
|
|
require.NoError(t, ds.ReconcileSoftwareTitles(ctx))
|
|
|
|
|
require.NoError(t, ds.SyncHostsSoftwareTitles(ctx, time.Now()))
|
|
|
|
|
|
|
|
|
|
// List software titles for "All teams", should only return the host software titles
|
|
|
|
|
// and no installers/VPP-apps because none is installed yet.
|
|
|
|
|
titles, counts, _, err := ds.ListSoftwareTitles(
|
|
|
|
|
ctx,
|
|
|
|
|
fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: nil,
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.EqualValues(t, 2, counts)
|
|
|
|
|
assert.Len(t, titles, 2)
|
|
|
|
|
type nameSource struct {
|
|
|
|
|
name string
|
|
|
|
|
source string
|
|
|
|
|
}
|
|
|
|
|
names := make([]nameSource, 0, len(titles))
|
|
|
|
|
for _, title := range titles {
|
|
|
|
|
names = append(names, nameSource{name: title.Name, source: title.Source})
|
|
|
|
|
}
|
|
|
|
|
assert.ElementsMatch(t, []nameSource{
|
|
|
|
|
{name: "bar", source: "deb_packages"},
|
|
|
|
|
{name: "foo", source: "chrome_extensions"},
|
|
|
|
|
}, names)
|
|
|
|
|
|
|
|
|
|
// List software for "No team". Should list the host's software + the macOS installer.
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(
|
|
|
|
|
ctx,
|
|
|
|
|
fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.EqualValues(t, 3, counts)
|
|
|
|
|
assert.Len(t, titles, 3)
|
|
|
|
|
names = make([]nameSource, 0, len(titles))
|
|
|
|
|
for _, title := range titles {
|
|
|
|
|
names = append(names, nameSource{name: title.Name, source: title.Source})
|
|
|
|
|
}
|
|
|
|
|
assert.ElementsMatch(t, []nameSource{
|
|
|
|
|
{name: "bar", source: "deb_packages"},
|
|
|
|
|
{name: "foo", source: "chrome_extensions"},
|
|
|
|
|
{name: "foobar", source: "apps"},
|
|
|
|
|
}, names)
|
|
|
|
|
|
|
|
|
|
// List software for "team1". Should list Canva for iOS and macOS.
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(
|
|
|
|
|
ctx,
|
|
|
|
|
fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: &team1.ID,
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.EqualValues(t, 2, counts)
|
|
|
|
|
assert.Len(t, titles, 2)
|
|
|
|
|
names = make([]nameSource, 0, len(titles))
|
|
|
|
|
for _, title := range titles {
|
|
|
|
|
names = append(names, nameSource{name: title.Name, source: title.Source})
|
|
|
|
|
}
|
|
|
|
|
assert.ElementsMatch(t, []nameSource{
|
|
|
|
|
{name: "Canva", source: "ios_apps"},
|
|
|
|
|
{name: "Canva", source: "apps"},
|
|
|
|
|
}, names)
|
|
|
|
|
|
|
|
|
|
// List software for "team2". Should list Canva for iPadOS.
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(
|
|
|
|
|
ctx,
|
|
|
|
|
fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
TeamID: &team2.ID,
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
assert.EqualValues(t, 1, counts)
|
|
|
|
|
assert.Len(t, titles, 1)
|
|
|
|
|
names = make([]nameSource, 0, len(titles))
|
|
|
|
|
for _, title := range titles {
|
|
|
|
|
names = append(names, nameSource{name: title.Name, source: title.Source})
|
|
|
|
|
}
|
|
|
|
|
assert.ElementsMatch(t, []nameSource{
|
|
|
|
|
{name: "Canva", source: "ipados_apps"},
|
|
|
|
|
}, names)
|
|
|
|
|
|
|
|
|
|
// List software available for install on "No team". Should list "foobar" package only.
|
|
|
|
|
titles, counts, _, err = ds.ListSoftwareTitles(
|
|
|
|
|
ctx,
|
|
|
|
|
fleet.SoftwareTitleListOptions{
|
|
|
|
|
ListOptions: fleet.ListOptions{
|
|
|
|
|
OrderKey: "name",
|
|
|
|
|
OrderDirection: fleet.OrderAscending,
|
|
|
|
|
},
|
|
|
|
|
AvailableForInstall: true,
|
|
|
|
|
TeamID: ptr.Uint(0),
|
|
|
|
|
},
|
|
|
|
|
fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}},
|
|
|
|
|
)
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
require.EqualValues(t, 1, counts)
|
|
|
|
|
require.Len(t, titles, 1)
|
|
|
|
|
|
|
|
|
|
names = make([]nameSource, 0, len(titles))
|
|
|
|
|
for _, title := range titles {
|
|
|
|
|
names = append(names, nameSource{name: title.Name, source: title.Source})
|
|
|
|
|
}
|
|
|
|
|
assert.ElementsMatch(t, []nameSource{
|
|
|
|
|
{name: "foobar", source: "apps"},
|
|
|
|
|
}, names)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func testUploadedSoftwareExists(t *testing.T, ds *Datastore) {
|
|
|
|
|
ctx := context.Background()
|
|
|
|
|
|
|
|
|
|