31581 Fix packages_only flag to only show items with software_package (#32284)
Closes #31581 Note: - When no team id is provided it lists all installers, but they don't have software_package fielded. I don't know if this is the intended behavior or not. # 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] Added/updated automated tests - [x] QA'd all new/changed functionality manually
This commit is contained in:
@@ -113,6 +113,10 @@ func (ds *Datastore) ListSoftwareTitles(
|
||||
return nil, 0, nil, fleet.NewInvalidArgumentError("query", "min_cvss_score, max_cvss_score, and exploit can only be provided with vulnerable=true")
|
||||
}
|
||||
|
||||
if opt.TeamID == nil && opt.PackagesOnly {
|
||||
return nil, 0, nil, fleet.NewInvalidArgumentError("query", "packages_only can only be provided with team_id")
|
||||
}
|
||||
|
||||
dbReader := ds.reader(ctx)
|
||||
getTitlesStmt, args, err := selectSoftwareTitlesSQL(opt)
|
||||
if err != nil {
|
||||
@@ -354,7 +358,8 @@ SELECT
|
||||
{{end}}
|
||||
FROM software_titles st
|
||||
{{if hasTeamID .}}
|
||||
LEFT JOIN software_installers si ON si.title_id = st.id AND si.global_or_team_id = {{teamID .}}
|
||||
{{$installerJoin := printf "%s JOIN software_installers si ON si.title_id = st.id AND si.global_or_team_id = %d" (yesNo .PackagesOnly "INNER" "LEFT") (teamID .)}}
|
||||
{{$installerJoin}}
|
||||
LEFT JOIN vpp_apps vap ON vap.title_id = st.id AND {{yesNo .PackagesOnly "FALSE" "TRUE"}}
|
||||
LEFT JOIN vpp_apps_teams vat ON vat.adam_id = vap.adam_id AND vat.platform = vap.platform AND
|
||||
{{if .PackagesOnly}} FALSE {{else}} vat.global_or_team_id = {{teamID .}}{{end}}
|
||||
@@ -395,8 +400,11 @@ WHERE
|
||||
{{end}}
|
||||
{{$additionalWhere}}
|
||||
{{end}}
|
||||
-- If teamID is set, defaults to "a software installer or VPP app exists", and see next condition.
|
||||
{{with $defFilter := yesNo (hasTeamID .) "(si.id IS NOT NULL OR vat.adam_id IS NOT NULL)" "FALSE"}}
|
||||
{{with $defFilter := "FALSE"}}
|
||||
-- If teamID is set and PackagesOnly is false, defaults to "a software installer or VPP app exists", and see next condition.
|
||||
{{if and (hasTeamID $) (not $.PackagesOnly) }}
|
||||
{{$defFilter = "(si.id IS NOT NULL OR vat.adam_id IS NOT NULL)"}}
|
||||
{{end}}
|
||||
-- add software installed for hosts if we're not filtering for "available for install" only
|
||||
{{if not $.AvailableForInstall}}
|
||||
{{$defFilter = $defFilter | printf " ( %s OR sthc.hosts_count > 0 ) "}}
|
||||
|
||||
@@ -41,6 +41,7 @@ func TestSoftwareTitles(t *testing.T) {
|
||||
{"UpdateSoftwareTitleName", testUpdateSoftwareTitleName},
|
||||
{"ListSoftwareTitlesDoesnotIncludeDuplicates", testListSoftwareTitlesDoesnotIncludeDuplicates},
|
||||
{"ListSoftwareTitlesAllTeamsWithAutomaticInstallersInNoTeam", testListSoftwareTitlesAllTeamsWithAutomaticInstallersInNoTeam},
|
||||
{"ListSoftwareTitlesPackagesOnly", testSoftwareTitlesPackagesOnly},
|
||||
}
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
@@ -2073,3 +2074,87 @@ func testListSoftwareTitlesAllTeamsWithAutomaticInstallersInNoTeam(t *testing.T,
|
||||
require.Len(t, allTeamsTitles, 1)
|
||||
require.Nil(t, allTeamsTitles[0].SoftwarePackage)
|
||||
}
|
||||
|
||||
func testSoftwareTitlesPackagesOnly(t *testing.T, ds *Datastore) {
|
||||
ctx := context.Background()
|
||||
|
||||
team1, err := ds.NewTeam(ctx, &fleet.Team{Name: "team1"})
|
||||
require.NoError(t, err)
|
||||
|
||||
host := test.NewHost(t, ds, "host1", "", "host1key", "host1uuid", time.Now())
|
||||
require.NoError(t, ds.AddHostsToTeam(ctx, fleet.NewAddHostsToTeamParams(&team1.ID, []uint{host.ID})))
|
||||
|
||||
user := test.NewUser(t, ds, "Alice", "alice@example.com", true)
|
||||
|
||||
software := []fleet.Software{
|
||||
{Name: "foo", Version: "1.0.0", Source: "deb_packages"},
|
||||
{Name: "bar", Version: "2.0.0", Source: "apps"},
|
||||
{Name: "baz", Version: "3.0.0", Source: "rpm_packages"},
|
||||
}
|
||||
_, err = ds.UpdateHostSoftware(ctx, host.ID, software)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = ds.MatchOrCreateSoftwareInstaller(ctx, &fleet.UploadSoftwareInstallerPayload{
|
||||
Title: "foo",
|
||||
Source: "deb_packages",
|
||||
InstallScript: "echo foo",
|
||||
Filename: "foo.pkg",
|
||||
UserID: user.ID,
|
||||
TeamID: &team1.ID,
|
||||
ValidatedLabels: &fleet.LabelIdentsWithScope{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
_, _, err = ds.MatchOrCreateSoftwareInstaller(ctx, &fleet.UploadSoftwareInstallerPayload{
|
||||
Title: "bar",
|
||||
Source: "apps",
|
||||
InstallScript: "echo bar",
|
||||
Filename: "bar.pkg",
|
||||
UserID: user.ID,
|
||||
TeamID: &team1.ID,
|
||||
ValidatedLabels: &fleet.LabelIdentsWithScope{},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Sync and reconcile
|
||||
require.NoError(t, ds.SyncHostsSoftware(ctx, time.Now()))
|
||||
require.NoError(t, ds.ReconcileSoftwareTitles(ctx))
|
||||
require.NoError(t, ds.SyncHostsSoftwareTitles(ctx, time.Now()))
|
||||
|
||||
t.Run("packages_only=false no team_id", func(t *testing.T) {
|
||||
titles, _, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
||||
PackagesOnly: false,
|
||||
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, titles, 3)
|
||||
})
|
||||
|
||||
t.Run("packages_only=true no team_id", func(t *testing.T) {
|
||||
_, _, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
||||
PackagesOnly: true,
|
||||
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "packages_only can only be provided with team_id")
|
||||
})
|
||||
|
||||
t.Run("packages_only=false with team_id", func(t *testing.T) {
|
||||
titles, _, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
||||
PackagesOnly: false,
|
||||
TeamID: &team1.ID,
|
||||
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, titles, 3)
|
||||
})
|
||||
|
||||
t.Run("packages_only=true with team_id", func(t *testing.T) {
|
||||
titles, _, _, err := ds.ListSoftwareTitles(ctx, fleet.SoftwareTitleListOptions{
|
||||
PackagesOnly: true,
|
||||
TeamID: &team1.ID,
|
||||
}, fleet.TeamFilter{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
|
||||
require.NoError(t, err)
|
||||
require.Len(t, titles, 2)
|
||||
for _, title := range titles {
|
||||
require.NotNil(t, title.SoftwarePackage)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user