From 3123324fe069eeca75aacf9f7c05986854c982a8 Mon Sep 17 00:00:00 2001 From: Jahziel Villasana-Espinoza Date: Tue, 24 Dec 2024 12:30:46 -0500 Subject: [PATCH] fix: add missing field (#24977) > Related issue: #24970 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [x] Added/updated tests - [x] Manual QA for all new/changed functionality --- docs/Contributing/Audit-logs.md | 2 + ee/server/service/software_installers.go | 6 ++ server/fleet/activities.go | 3 + server/service/integration_enterprise_test.go | 18 ++++- server/service/testing_client.go | 68 +++++++++++++++++++ 5 files changed, 95 insertions(+), 2 deletions(-) diff --git a/docs/Contributing/Audit-logs.md b/docs/Contributing/Audit-logs.md index fc393fe5c03a..feadc6e0cda6 100644 --- a/docs/Contributing/Audit-logs.md +++ b/docs/Contributing/Audit-logs.md @@ -1278,6 +1278,7 @@ This activity contains the following fields: - "team_name": Name of the team on which this software was updated. `null` if it was updated on no team. - "team_id": The ID of the team on which this software was updated. `null` if it was updated on no team. - "self_service": Whether the software is available for installation by the end user. +- "software_title_id": ID of the added software title. - "labels_include_any": Target hosts that have any label in the array. - "labels_exclude_any": Target hosts that don't have any label in the array. @@ -1290,6 +1291,7 @@ This activity contains the following fields: "team_name": "Workstations", "team_id": 123, "self_service": true, + "software_title_id": 2234, "labels_include_any": [ { "name": "Engineering", diff --git a/ee/server/service/software_installers.go b/ee/server/service/software_installers.go index 1773770fad65..67c81f7d44ba 100644 --- a/ee/server/service/software_installers.go +++ b/ee/server/service/software_installers.go @@ -264,6 +264,12 @@ func (svc *Service) UpdateSoftwareInstaller(ctx context.Context, payload *fleet. TeamID: actTeamID, SelfService: existingInstaller.SelfService, SoftwarePackage: &existingInstaller.Name, + SoftwareTitleID: payload.TitleID, + } + + if payload.SelfService != nil && *payload.SelfService != existingInstaller.SelfService { + dirty["SelfService"] = true + activity.SelfService = *payload.SelfService } var payloadForNewInstallerFile *fleet.UploadSoftwareInstallerPayload diff --git a/server/fleet/activities.go b/server/fleet/activities.go index 531a598fcafe..fcc70fe610e8 100644 --- a/server/fleet/activities.go +++ b/server/fleet/activities.go @@ -1720,6 +1720,7 @@ type ActivityTypeEditedSoftware struct { SelfService bool `json:"self_service"` LabelsIncludeAny []ActivitySoftwareLabel `json:"labels_include_any,omitempty"` LabelsExcludeAny []ActivitySoftwareLabel `json:"labels_exclude_any,omitempty"` + SoftwareTitleID uint `json:"software_title_id"` } func (a ActivityTypeEditedSoftware) ActivityName() string { @@ -1733,6 +1734,7 @@ func (a ActivityTypeEditedSoftware) Documentation() (string, string, string) { - "team_name": Name of the team on which this software was updated.` + " `null` " + `if it was updated on no team. - "team_id": The ID of the team on which this software was updated.` + " `null` " + `if it was updated on no team. - "self_service": Whether the software is available for installation by the end user. +- "software_title_id": ID of the added software title. - "labels_include_any": Target hosts that have any label in the array. - "labels_exclude_any": Target hosts that don't have any label in the array.`, `{ "software_title": "Falcon.app", @@ -1740,6 +1742,7 @@ func (a ActivityTypeEditedSoftware) Documentation() (string, string, string) { "team_name": "Workstations", "team_id": 123, "self_service": true, + "software_title_id": 2234, "labels_include_any": [ { "name": "Engineering", diff --git a/server/service/integration_enterprise_test.go b/server/service/integration_enterprise_test.go index 9059b18181d8..73e47a147aa2 100644 --- a/server/service/integration_enterprise_test.go +++ b/server/service/integration_enterprise_test.go @@ -10790,6 +10790,20 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD // upload again fails s.uploadSoftwareInstaller(t, payload, http.StatusConflict, "already exists") + // update should succeed + s.updateSoftwareInstaller(t, &fleet.UpdateSoftwareInstallerPayload{ + SelfService: ptr.Bool(true), + InstallScript: ptr.String("some install script"), + PreInstallQuery: ptr.String("some pre install query"), + PostInstallScript: ptr.String("some post install script"), + Filename: "ruby.deb", + TitleID: titleID, + TeamID: nil, + }, http.StatusOK, "") + activityData = fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": null, + "team_id": null, "self_service": true, "software_title_id": %d, "labels_include_any": [{"id": %d, "name": %q}]}`, + titleID, labelResp.Label.ID, t.Name()) + s.lastActivityMatches(fleet.ActivityTypeEditedSoftware{}.ActivityName(), activityData, 0) // patch the software installer to change the labels body, headers := generateMultipartRequest(t, "", "", nil, s.token, map[string][]string{ "team_id": {"0"}, @@ -10847,8 +10861,8 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD s.DoRawWithHeaders("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package", titleID), body.Bytes(), http.StatusOK, headers) activityData = fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "team_name": null, - "team_id": null, "self_service": true, "labels_include_any": [{"id": %d, "name": %q}]}`, - labelResp.Label.ID, labelResp.Label.Name) + "team_id": null, "self_service": true, "labels_include_any": [{"id": %d, "name": %q}], "software_title_id": %d}`, + labelResp.Label.ID, labelResp.Label.Name, titleID) s.lastActivityMatches(fleet.ActivityTypeEditedSoftware{}.ActivityName(), activityData, 0) // orbit-downloading fails with invalid orbit node key diff --git a/server/service/testing_client.go b/server/service/testing_client.go index df46710cd13a..a8f2183d1aa6 100644 --- a/server/service/testing_client.go +++ b/server/service/testing_client.go @@ -614,3 +614,71 @@ func (ts *withServer) uploadSoftwareInstaller( require.Contains(t, errMsg, expectedError) } } + +func (ts *withServer) updateSoftwareInstaller( + t *testing.T, + payload *fleet.UpdateSoftwareInstallerPayload, + expectedStatus int, + expectedError string, +) { + t.Helper() + + tfr, err := fleet.NewKeepFileReader(filepath.Join("testdata", "software-installers", payload.Filename)) + require.NoError(t, err) + defer tfr.Close() + + payload.InstallerFile = tfr + + var b bytes.Buffer + w := multipart.NewWriter(&b) + + // add the software field + fw, err := w.CreateFormFile("software", payload.Filename) + require.NoError(t, err) + n, err := io.Copy(fw, payload.InstallerFile) + require.NoError(t, err) + require.NotZero(t, n) + + // add the team_id field + var tmID uint + if payload.TeamID != nil { + tmID = *payload.TeamID + } + require.NoError(t, w.WriteField("team_id", fmt.Sprintf("%d", tmID))) + // add the remaining fields + if payload.InstallScript != nil { + require.NoError(t, w.WriteField("install_script", *payload.InstallScript)) + } + if payload.PreInstallQuery != nil { + require.NoError(t, w.WriteField("pre_install_query", *payload.PreInstallQuery)) + } + if payload.PostInstallScript != nil { + require.NoError(t, w.WriteField("post_install_script", *payload.PostInstallScript)) + } + if payload.UninstallScript != nil { + require.NoError(t, w.WriteField("uninstall_script", *payload.UninstallScript)) + } + if payload.SelfService != nil { + if *payload.SelfService { + require.NoError(t, w.WriteField("self_service", "true")) + } else { + require.NoError(t, w.WriteField("self_service", "false")) + } + } + + w.Close() + + headers := map[string]string{ + "Content-Type": w.FormDataContentType(), + "Accept": "application/json", + "Authorization": fmt.Sprintf("Bearer %s", ts.token), + } + + r := ts.DoRawWithHeaders("PATCH", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package", payload.TitleID), b.Bytes(), expectedStatus, headers) + defer r.Body.Close() + + if expectedError != "" { + errMsg := extractServerErrorText(r.Body) + require.Contains(t, errMsg, expectedError) + } +}