add ddm declarations in the API (#17880)

for #17409
This commit is contained in:
Roberto Dip 2024-03-27 09:53:43 -03:00 committed by GitHub
parent 7b13d9ce17
commit fdc5aa57c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 102 additions and 10 deletions

View file

@ -1317,6 +1317,56 @@ func (a ActivityTypeWipedHost) Documentation() (activity, details, detailsExampl
}`
}
type ActivityTypeCreatedDeclarationProfile struct {
ProfileName string `json:"profile_name"`
Identifier string `json:"identifier"`
TeamID *uint `json:"team_id"`
TeamName *string `json:"team_name"`
}
func (a ActivityTypeCreatedDeclarationProfile) ActivityName() string {
return "created_declaration_profile"
}
func (a ActivityTypeCreatedDeclarationProfile) Documentation() (activity string, details string, detailsExample string) {
return `Generated when a user adds a new macOS declaration to a team (or no team).`,
`This activity contains the following fields:
- "profile_name": Name of the declaration.
- "identifier": Identifier of the declaration.
- "team_id": The ID of the team that the declaration applies to, ` + "`null`" + ` if it applies to devices that are not in a team.
- "team_name": The name of the team that the declaration applies to, ` + "`null`" + ` if it applies to devices that are not in a team.`, `{
"profile_name": "Passcode requirements",
"profile_identifier": "com.my.declaration",
"team_id": 123,
"team_name": "Workstations"
}`
}
type ActivityTypeDeletedDeclarationProfile struct {
ProfileName string `json:"profile_name"`
Identifier string `json:"identifier"`
TeamID *uint `json:"team_id"`
TeamName *string `json:"team_name"`
}
func (a ActivityTypeDeletedDeclarationProfile) ActivityName() string {
return "deleted_declaration_profile"
}
func (a ActivityTypeDeletedDeclarationProfile) Documentation() (activity string, details string, detailsExample string) {
return `Generated when a user removes a macOS declaration from a team (or no team).`,
`This activity contains the following fields:
- "profile_name": Name of the declaration.
- "identifier": Identifier of the declaration.
- "team_id": The ID of the team that the declaration applies to, ` + "`null`" + ` if it applies to devices that are not in a team.
- "team_name": The name of the team that the declaration applies to, ` + "`null`" + ` if it applies to devices that are not in a team.`, `{
"profile_name": "Passcode requirements",
"profile_identifier": "com.my.declaration",
"team_id": 123,
"team_name": "Workstations"
}`
}
// LogRoleChangeActivities logs activities for each role change, globally and one for each change in teams.
func LogRoleChangeActivities(ctx context.Context, ds Datastore, adminUser *User, oldGlobalRole *string, oldTeamRoles []UserTeam, user *User) error {
if user.GlobalRole != nil && (oldGlobalRole == nil || *oldGlobalRole != *user.GlobalRole) {

View file

@ -406,6 +406,15 @@ func (svc *Service) NewMDMAppleDeclaration(ctx context.Context, teamID uint, r i
return nil, err
}
var teamName string
if teamID >= 1 {
tm, err := svc.EnterpriseOverrides.TeamByIDOrName(ctx, &teamID, nil)
if err != nil {
return nil, ctxerr.Wrap(ctx, err)
}
teamName = tm.Name
}
data, err := io.ReadAll(r)
if err != nil {
return nil, err
@ -442,6 +451,23 @@ func (svc *Service) NewMDMAppleDeclaration(ctx context.Context, teamID uint, r i
return nil, err
}
var (
actTeamID *uint
actTeamName *string
)
if teamID > 0 {
actTeamID = &teamID
actTeamName = &teamName
}
if err := svc.ds.NewActivity(ctx, authz.UserFromContext(ctx), &fleet.ActivityTypeCreatedDeclarationProfile{
TeamID: actTeamID,
TeamName: actTeamName,
ProfileName: decl.Name,
Identifier: decl.Identifier,
}); err != nil {
return nil, ctxerr.Wrap(ctx, err, "logging activity for create mdm apple declaration")
}
return decl, nil
}
@ -802,13 +828,10 @@ func (svc *Service) DeleteMDMAppleDeclaration(ctx context.Context, declUUID stri
return ctxerr.Wrap(ctx, err)
}
// TODO: confirm if bulk set pending host profiles is needed
// cannot use the profile ID as it is now deleted
if err := svc.ds.BulkSetPendingMDMHostProfiles(ctx, nil, []uint{teamID}, nil, nil); err != nil {
return ctxerr.Wrap(ctx, err, "bulk set pending host profiles")
}
// TODO: confirm activity type
var (
actTeamID *uint
actTeamName *string
@ -817,11 +840,11 @@ func (svc *Service) DeleteMDMAppleDeclaration(ctx context.Context, declUUID stri
actTeamID = &teamID
actTeamName = &teamName
}
if err := svc.ds.NewActivity(ctx, authz.UserFromContext(ctx), &fleet.ActivityTypeDeletedMacosProfile{
TeamID: actTeamID,
TeamName: actTeamName,
ProfileName: decl.Name,
ProfileIdentifier: decl.Identifier,
if err := svc.ds.NewActivity(ctx, authz.UserFromContext(ctx), &fleet.ActivityTypeDeletedDeclarationProfile{
TeamID: actTeamID,
TeamName: actTeamName,
ProfileName: decl.Name,
Identifier: decl.Identifier,
}); err != nil {
return ctxerr.Wrap(ctx, err, "logging activity for delete mdm apple declaration")
}

View file

@ -9331,6 +9331,20 @@ func (s *integrationMDMTestSuite) TestMDMConfigProfileCRUD() {
return uid
}
createAppleDeclaration := func(name, ident string, teamID uint, labelNames []string) string {
uid := assertAppleDeclaration(name+".json", ident, teamID, labelNames, http.StatusOK, "")
var wantJSON string
if teamID == 0 {
wantJSON = fmt.Sprintf(`{"team_id": null, "team_name": null, "profile_name": %q, "identifier": %q}`, name, ident)
} else {
wantJSON = fmt.Sprintf(`{"team_id": %d, "team_name": %q, "profile_name": %q, "identifier": %q}`, teamID, testTeam.Name, name, ident)
}
s.lastActivityOfTypeMatches(fleet.ActivityTypeCreatedDeclarationProfile{}.ActivityName(), wantJSON, 0)
return uid
}
assertWindowsProfile := func(filename, locURI string, teamID uint, labelNames []string, wantStatus int, wantErrMsg string) string {
fields := map[string][]string{
"labels": labelNames,
@ -9399,7 +9413,7 @@ func (s *integrationMDMTestSuite) TestMDMConfigProfileCRUD() {
assertAppleProfile("win-team-profile.mobileconfig", "win-team-profile", "test-team-ident-2", 0, nil, http.StatusOK, "")
// add some macOS declarations
assertAppleDeclaration("apple-declaration.json", "test-declaration-ident", 0, nil, http.StatusOK, "")
createAppleDeclaration("apple-declaration", "test-declaration-ident", 0, nil)
// identifier must be unique, it conflicts with existing declaration
assertAppleDeclaration("apple-declaration.json", "test-declaration-ident", 0, nil, http.StatusConflict, "test-declaration-ident already exists")
// name is pulled from filename, it conflicts with existing declaration
@ -9451,7 +9465,7 @@ func (s *integrationMDMTestSuite) TestMDMConfigProfileCRUD() {
// profiles with valid labels
uuidAppleWithLabel := assertAppleProfile("apple-profile-with-labels.mobileconfig", "apple-profile-with-labels", "ident-with-labels", 0, []string{"foo"}, http.StatusOK, "")
uuidAppleDDMWithLabel := assertAppleDeclaration("apple-decl-with-labels.json", "ident-decl-with-labels", 0, []string{"foo"}, http.StatusOK, "")
uuidAppleDDMWithLabel := createAppleDeclaration("apple-decl-with-labels", "ident-decl-with-labels", 0, []string{"foo"})
uuidWindowsWithLabel := assertWindowsProfile("win-profile-with-labels.xml", "./Test", 0, []string{"foo", "bar"}, http.StatusOK, "")
// verify that the label associations have been created
@ -9558,6 +9572,11 @@ func (s *integrationMDMTestSuite) TestMDMConfigProfileCRUD() {
// delete existing Apple declaration
s.DoJSON("DELETE", fmt.Sprintf("/api/latest/fleet/configuration_profiles/%s", uuidAppleDDMWithLabel), nil, http.StatusOK, &deleteResp)
s.lastActivityOfTypeMatches(
fleet.ActivityTypeDeletedDeclarationProfile{}.ActivityName(),
`{"profile_name": "apple-decl-with-labels", "identifier": "ident-decl-with-labels", "team_id": null, "team_name": null}`,
0,
)
// delete non-existing Apple declaration
s.DoJSON("DELETE", fmt.Sprintf("/api/latest/fleet/configuration_profiles/%s", fmt.Sprintf("%sno-such-profile", fleet.MDMAppleDeclarationUUIDPrefix)), nil, http.StatusNotFound, &deleteResp)
// delete existing Windows profiles