diff --git a/changes/30197-automatic-install-policies b/changes/30197-automatic-install-policies new file mode 100644 index 0000000000..52f46b948c --- /dev/null +++ b/changes/30197-automatic-install-policies @@ -0,0 +1 @@ +* Added automatic install policies into host software responses \ No newline at end of file diff --git a/server/datastore/mysql/software.go b/server/datastore/mysql/software.go index 10311179bc..3695ee639c 100644 --- a/server/datastore/mysql/software.go +++ b/server/datastore/mysql/software.go @@ -3792,8 +3792,10 @@ func (ds *Datastore) ListHostSoftware(ctx context.Context, host *fleet.Host, opt } var vppAdamIDs []string - for key := range byVPPAdamID { + var vppTitleIds []uint + for key, v := range byVPPAdamID { vppAdamIDs = append(vppAdamIDs, key) + vppTitleIds = append(vppTitleIds, v.ID) } var titleCount uint @@ -4126,6 +4128,17 @@ func (ds *Datastore) ListHostSoftware(ctx context.Context, host *fleet.Host, opt vulnerabilitiesBySoftwareID[cve.SoftwareID] = append(vulnerabilitiesBySoftwareID[cve.SoftwareID], cve.CVE) } + // Grab the automatic install policies, if any exist + policies, err := ds.getPoliciesBySoftwareTitleIDs(ctx, append(vppTitleIds, softwareTitleIds...), host.TeamID) + if err != nil { + return nil, nil, ctxerr.Wrap(ctx, err, "batch getting policies by software title IDs") + } + + policiesBySoftwareTitleId := make(map[uint][]fleet.AutomaticInstallPolicy, len(policies)) + for _, p := range policies { + policiesBySoftwareTitleId[p.TitleID] = append(policiesBySoftwareTitleId[p.TitleID], p) + } + indexOfSoftwareTitle := make(map[uint]uint) deduplicatedList := make([]*hostSoftware, 0, len(hostSoftwareList)) for _, softwareTitleRecord := range hostSoftwareList { @@ -4268,6 +4281,14 @@ func (ds *Datastore) ListHostSoftware(ctx context.Context, host *fleet.Host, opt } } + if policies, ok := policiesBySoftwareTitleId[softwareTitleRecord.ID]; ok { + if softwareTitleRecord.AppStoreApp != nil { + softwareTitleRecord.AppStoreApp.AutomaticInstallPolicies = policies + } else { + softwareTitleRecord.SoftwarePackage.AutomaticInstallPolicies = policies + } + } + if _, ok := indexOfSoftwareTitle[softwareTitleRecord.ID]; !ok { indexOfSoftwareTitle[softwareTitleRecord.ID] = uint(len(deduplicatedList)) deduplicatedList = append(deduplicatedList, softwareTitleRecord) diff --git a/server/datastore/mysql/software_test.go b/server/datastore/mysql/software_test.go index 84e42292b2..c2e3aa7ca7 100644 --- a/server/datastore/mysql/software_test.go +++ b/server/datastore/mysql/software_test.go @@ -3702,6 +3702,13 @@ func testListHostSoftware(t *testing.T, ds *Datastore) { assert.Equal(t, e.SoftwarePackage.LastUninstall.ExecutionID, g.SoftwarePackage.LastUninstall.ExecutionID) assert.NotNil(t, g.SoftwarePackage.LastUninstall.UninstalledAt) } + if e.SoftwarePackage.AutomaticInstallPolicies != nil { + require.Len(t, e.SoftwarePackage.AutomaticInstallPolicies, len(g.SoftwarePackage.AutomaticInstallPolicies)) + for i, p := range e.SoftwarePackage.AutomaticInstallPolicies { + require.Equal(t, p.ID, g.SoftwarePackage.AutomaticInstallPolicies[i].ID) + require.Equal(t, p.Name, g.SoftwarePackage.AutomaticInstallPolicies[i].Name) + } + } } if e.AppStoreApp != nil { @@ -3716,6 +3723,13 @@ func testListHostSoftware(t *testing.T, ds *Datastore) { require.Equal(t, e.AppStoreApp.LastInstall.CommandUUID, g.AppStoreApp.LastInstall.CommandUUID) require.NotNil(t, g.AppStoreApp.LastInstall.InstalledAt) } + if e.AppStoreApp.AutomaticInstallPolicies != nil { + require.Len(t, e.AppStoreApp.AutomaticInstallPolicies, len(g.AppStoreApp.AutomaticInstallPolicies)) + for i, p := range e.AppStoreApp.AutomaticInstallPolicies { + require.Equal(t, p.ID, g.AppStoreApp.AutomaticInstallPolicies[i].ID) + require.Equal(t, p.Name, g.AppStoreApp.AutomaticInstallPolicies[i].Name) + } + } } // require.Equal(t, e.SoftwarePackage, g.SoftwarePackage) // require.Equal(t, e.AppStoreApp, g.AppStoreApp) @@ -4220,6 +4234,33 @@ func testListHostSoftware(t *testing.T, ds *Datastore) { i3.Name + i3.Source: expected[i3.Name+i3.Source], }, sw, true) + // add policies to software + policy1 := newTestPolicy(t, ds, user, "policy 1", "darwin", &tm.ID) + policy1.SoftwareInstallerID = ptr.Uint(swi5Tm) + err = ds.SavePolicy(context.Background(), policy1, false, false) + require.NoError(t, err) + policy2 := newTestPolicy(t, ds, user, "policy 2", "darwin", &tm.ID) + policy2.SoftwareInstallerID = ptr.Uint(swi5Tm) + err = ds.SavePolicy(context.Background(), policy2, false, false) + require.NoError(t, err) + sw, meta, err = ds.ListHostSoftware(ctx, tmHost, opts) + require.NoError(t, err) + require.Equal(t, &fleet.PaginationMetadata{TotalResults: 1}, meta) + expectedWithPolicies := map[string]fleet.HostSoftwareWithInstaller{ + i3.Name + i3.Source: expected[i3.Name+i3.Source], + } + expectedWithPolicies[i3.Name+i3.Source].SoftwarePackage.AutomaticInstallPolicies = []fleet.AutomaticInstallPolicy{ + { + ID: policy1.ID, + Name: policy1.Name, + }, + { + ID: policy2.ID, + Name: policy2.Name, + }, + } + compareResults(expectedWithPolicies, sw, true) + // test with a search query (searches on name), with and without available software opts.ListOptions.MatchQuery = "a" opts.IncludeAvailableForInstall = false @@ -4260,7 +4301,7 @@ func testListHostSoftware(t *testing.T, ds *Datastore) { BundleIdentifier: "com.app.vpp1", }, nil) require.NoError(t, err) - _, err = ds.InsertVPPAppWithTeam(ctx, + vatm1, err := ds.InsertVPPAppWithTeam(ctx, &fleet.VPPApp{ VPPAppTeam: fleet.VPPAppTeam{VPPAppID: fleet.VPPAppID{AdamID: "adam_vpp_1", Platform: fleet.MacOSPlatform}}, Name: "vpp1", BundleIdentifier: "com.app.vpp1", @@ -4303,6 +4344,20 @@ func testListHostSoftware(t *testing.T, ds *Datastore) { vpp1TmCmdUUID := createVPPAppInstallRequest(t, ds, tmHost, vpp1, user) require.NotEmpty(t, vpp1TmCmdUUID) + // add policies to vpp app 1 + va1FromDB, err := ds.GetVPPAppMetadataByAdamIDPlatformTeamID(ctx, vatm1.AdamID, vatm1.Platform, &tm.ID) + require.NoError(t, err) + + policy3 := newTestPolicy(t, ds, user, "policy 3", "darwin", &tm.ID) + policy3.VPPAppsTeamsID = &va1FromDB.AppTeamID + err = ds.SavePolicy(context.Background(), policy3, false, false) + require.NoError(t, err) + + policy4 := newTestPolicy(t, ds, user, "policy 4", "darwin", &tm.ID) + policy4.VPPAppsTeamsID = &va1FromDB.AppTeamID + err = ds.SavePolicy(context.Background(), policy4, false, false) + require.NoError(t, err) + opts.IncludeAvailableForInstall = false opts.ListOptions.MatchQuery = "" sw, meta, err = ds.ListHostSoftware(ctx, host, opts) @@ -4374,10 +4429,25 @@ 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.SoftwareInstallPending), - AppStoreApp: &fleet.SoftwarePackageOrApp{AppStoreID: vpp1, Platform: "darwin", SelfService: ptr.Bool(false), LastInstall: &fleet.HostSoftwareInstall{CommandUUID: vpp1TmCmdUUID}}, + Name: "vpp1", + Source: "apps", + Status: expectStatus(fleet.SoftwareInstallPending), + AppStoreApp: &fleet.SoftwarePackageOrApp{ + AppStoreID: vpp1, + Platform: "darwin", + SelfService: ptr.Bool(false), + LastInstall: &fleet.HostSoftwareInstall{CommandUUID: vpp1TmCmdUUID}, + AutomaticInstallPolicies: []fleet.AutomaticInstallPolicy{ + { + ID: policy3.ID, + Name: policy3.Name, + }, + { + ID: policy4.ID, + Name: policy4.Name, + }, + }, + }, }, }, sw, true)