Add label scope to create FMA endpoint (#24830)

This commit is contained in:
Sarah Gillespie 2024-12-17 12:12:08 -06:00 committed by GitHub
parent eb41e7ce8e
commit fa2c399cfc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 85 additions and 8 deletions

View file

@ -32,15 +32,17 @@ func (svc *Service) AddFleetMaintainedApp(
return 0, err
}
if len(labelsIncludeAny) > 0 && len(labelsExcludeAny) > 0 {
return 0, &fleet.BadRequestError{Message: `Only one of "labels_include_any" or "labels_exclude_any" can be included.`}
}
vc, ok := viewer.FromContext(ctx)
if !ok {
return 0, fleet.ErrNoContext
}
// validate labels before we do anything else
validatedLabels, err := svc.validateSoftwareLabels(ctx, labelsIncludeAny, labelsExcludeAny)
if err != nil {
return 0, ctxerr.Wrap(ctx, err, "validating software labels")
}
app, err := svc.ds.GetMaintainedAppByID(ctx, appID)
if err != nil {
return 0, ctxerr.Wrap(ctx, err, "getting maintained app by id")
@ -120,11 +122,9 @@ func (svc *Service) AddFleetMaintainedApp(
SelfService: selfService,
InstallScript: installScript,
UninstallScript: uninstallScript,
ValidatedLabels: validatedLabels,
}
// TODO: labels validations, for now just use empty struct
payload.ValidatedLabels = &fleet.LabelIdentsWithScope{}
// Create record in software installers table
_, titleID, err = svc.ds.MatchOrCreateSoftwareInstaller(ctx, payload)
if err != nil {

View file

@ -274,7 +274,7 @@ func setOrUpdateSoftwareInstallerLabelsDB(ctx context.Context, tx sqlx.ExtContex
return ctxerr.New(ctx, "invalid label scope")
}
stmt := `INSERT INTO software_installer_labels (software_installer_id, label_id, exclude) VALUES %s ON DUPLICATE KEY UPDATE software_installer_id = software_installer_id, label_id = label_id, exclude = VALUES(exclude)`
stmt := `INSERT INTO software_installer_labels (software_installer_id, label_id, exclude) VALUES %s ON DUPLICATE KEY UPDATE exclude = VALUES(exclude)`
var placeholders string
var insertArgs []interface{}
for _, lid := range labelIds {

View file

@ -15680,6 +15680,83 @@ func (s *integrationEnterpriseTestSuite) TestMaintainedApps() {
require.NotNil(t, policies[0].InstallSoftware)
require.Equal(t, tpResp.Policy.InstallSoftware.Name, policies[0].InstallSoftware.Name)
require.Equal(t, tpResp.Policy.InstallSoftware.SoftwareTitleID, policies[0].InstallSoftware.SoftwareTitleID)
// ===========================================================================================
// Adding label-scoped FMA
// ===========================================================================================
// Add some labels
var newLabelResp createLabelResponse
s.DoJSON("POST", "/api/v1/fleet/labels", fleet.LabelPayload{
Name: t.Name() + "1",
Platform: "darwin",
Query: "SELECT 1",
}, http.StatusOK, &newLabelResp)
lbl1 := newLabelResp.Label
s.DoJSON("POST", "/api/v1/fleet/labels", fleet.LabelPayload{
Name: t.Name() + "2",
Platform: "darwin",
Query: "SELECT 1",
}, http.StatusOK, &newLabelResp)
lbl2 := newLabelResp.Label
// Add another FMA
req = &addFleetMaintainedAppRequest{
AppID: 6,
SelfService: false,
PreInstallQuery: "SELECT 1",
InstallScript: "echo foo",
PostInstallScript: "echo done",
TeamID: ptr.Uint(0),
LabelsIncludeAny: []string{lbl1.Name, lbl2.Name},
}
addMAResp = addFleetMaintainedAppResponse{}
s.DoJSON("POST", "/api/latest/fleet/software/fleet_maintained_apps", req, http.StatusOK, &addMAResp)
require.NoError(t, addMAResp.Err)
require.NotEmpty(t, addMAResp.SoftwareTitleID)
// Get software title details
titleResp = getSoftwareTitleResponse{}
s.DoJSON(
"GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d", addMAResp.SoftwareTitleID),
getSoftwareTitleRequest{},
http.StatusOK, &titleResp,
"team_id", "0",
)
require.NotNil(t, titleResp.SoftwareTitle)
swTitle = titleResp.SoftwareTitle
require.NotNil(t, swTitle.SoftwarePackage)
require.Empty(t, swTitle.SoftwarePackage.LabelsExcludeAny)
require.Len(t, swTitle.SoftwarePackage.LabelsIncludeAny, 2)
gotNames := make(map[string]bool)
for _, lbl := range swTitle.SoftwarePackage.LabelsIncludeAny {
gotNames[lbl.LabelName] = true
}
require.True(t, gotNames[lbl1.Name])
require.True(t, gotNames[lbl2.Name])
// Can't set non-existent label
req = &addFleetMaintainedAppRequest{
AppID: 7,
SelfService: false,
PreInstallQuery: "SELECT 1",
InstallScript: "echo foo",
PostInstallScript: "echo done",
TeamID: ptr.Uint(0),
LabelsIncludeAny: []string{"no-such-label"},
}
addMAResp = addFleetMaintainedAppResponse{}
r = s.Do("POST", "/api/latest/fleet/software/fleet_maintained_apps", req, http.StatusBadRequest)
require.Contains(t, extractServerErrorText(r.Body), "some or all the labels provided don't exist")
// Can't set both labels_include_any and labels_exclude_any
req.LabelsIncludeAny = []string{lbl1.Name, lbl2.Name}
req.LabelsExcludeAny = []string{lbl1.Name}
addMAResp = addFleetMaintainedAppResponse{}
r = s.Do("POST", "/api/latest/fleet/software/fleet_maintained_apps", req, http.StatusBadRequest)
require.Contains(t, extractServerErrorText(r.Body), `Only one of "labels_include_any" or "labels_exclude_any" can be included`)
}
func (s *integrationEnterpriseTestSuite) TestWindowsMigrateMDMNotEnabled() {