Add MDM profiles to host detail in API responses (#10034)

Issue #9599 

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

- [ ] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [ ] Documented any API changes (docs/Using-Fleet/REST-API.md or
docs/Contributing/API-for-contributors.md)
- [ ] Documented any permissions changes
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.
- [ ] Added/updated tests
- [ ] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
This commit is contained in:
gillespi314
2023-02-22 16:26:06 -06:00
committed by GitHub
parent 48ca4bc26d
commit e31fc889f1
14 changed files with 333 additions and 15 deletions
+4
View File
@@ -265,6 +265,10 @@ func TestGetTeamsByName(t *testing.T) {
func TestGetHosts(t *testing.T) {
_, ds := runServerWithMockedDS(t)
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{}, nil
}
// this func is called when no host is specified i.e. `fleetctl get hosts --json`
ds.ListHostsFunc = func(ctx context.Context, filter fleet.TeamFilter, opt fleet.HostListOptions) ([]*fleet.Host, error) {
additional := json.RawMessage(`{"query1": [{"col1": "val", "col2": 42}]}`)
+2
View File
@@ -237,6 +237,7 @@ require (
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/kevinburke/ssh_config v1.1.0 // indirect
github.com/klauspost/compress v1.15.0 // indirect
github.com/lib/pq v1.10.6 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mattn/go-colorable v0.1.11 // indirect
@@ -287,6 +288,7 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
github.com/yashtewari/glob-intersection v0.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/ziutek/mymysql v1.5.4 // indirect
go.elastic.co/apm v1.15.0 // indirect
go.elastic.co/fastjson v1.1.0 // indirect
go.opencensus.io v0.23.0 // indirect
+2
View File
@@ -914,6 +914,7 @@ github.com/lib/pq v1.9.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.10.6 h1:jbk+ZieJ0D7EVGJYpL9QTz7/YW6UHbmdnZWYyK5cdBs=
github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/macadmins/osquery-extension v0.0.7 h1:iEo2eajSbG51pdXg+QH3kM5ZWhidWBBZ/YiNDEXU1lE=
@@ -1306,6 +1307,7 @@ github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPR
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
github.com/zwass/kit v0.0.0-20210625184505-ec5b5c5cce9c h1:TWQ2UvXPkhPxI2KmApKBOCaV6yD2N4mlvqFQ/DlPtpQ=
github.com/zwass/kit v0.0.0-20210625184505-ec5b5c5cce9c/go.mod h1:OYYulo9tUqRadRLwB0+LE914sa1ui2yL7OrcU3Q/1XY=
+19
View File
@@ -140,6 +140,25 @@ func (ds *Datastore) DeleteMDMAppleConfigProfile(ctx context.Context, profileID
return nil
}
func (ds *Datastore) GetHostMDMProfiles(ctx context.Context, hostUUID string) ([]fleet.HostMDMAppleProfile, error) {
stmt := `
SELECT
profile_id,
status,
operation_type,
detail
FROM
host_mdm_apple_profiles
WHERE
host_uuid = ?`
var profiles []fleet.HostMDMAppleProfile
if err := sqlx.SelectContext(ctx, ds.reader, &profiles, stmt, hostUUID); err != nil {
return nil, err
}
return profiles, nil
}
func (ds *Datastore) NewMDMAppleEnrollmentProfile(
ctx context.Context,
payload fleet.MDMAppleEnrollmentProfilePayload,
+119 -1
View File
@@ -27,6 +27,7 @@ func TestMDMAppleConfigProfile(t *testing.T) {
{"TestNewMDMAppleConfigProfileDuplicateIdentifier", testNewMDMAppleConfigProfileDuplicateIdentifier},
{"TestDeleteMDMAppleConfigProfile", testDeleteMDMAppleConfigProfile},
{"TestListMDMAppleConfigProfiles", testListMDMAppleConfigProfiles},
{"TestHostDetailsMDMProfiles", testHostDetailsMDMProfiles},
{"TestBatchSetMDMAppleProfiles", testBatchSetMDMAppleProfiles},
{"TestMDMAppleProfileManagement", testMDMAppleProfileManagement},
{"TestUpdateHostMDMAppleProfile", testGetMDMAppleProfilesContents},
@@ -192,6 +193,124 @@ func checkConfigProfile(t *testing.T, expected fleet.MDMAppleConfigProfile, actu
require.Equal(t, expected.Mobileconfig, actual.Mobileconfig)
}
func testHostDetailsMDMProfiles(t *testing.T, ds *Datastore) {
ctx := context.Background()
p0, err := ds.NewMDMAppleConfigProfile(ctx, fleet.MDMAppleConfigProfile{Name: "Name0", Identifier: "Identifier0", Mobileconfig: []byte("profile0-bytes")})
require.NoError(t, err)
p1, err := ds.NewMDMAppleConfigProfile(ctx, fleet.MDMAppleConfigProfile{Name: "Name1", Identifier: "Identifier1", Mobileconfig: []byte("profile1-bytes")})
require.NoError(t, err)
p2, err := ds.NewMDMAppleConfigProfile(ctx, fleet.MDMAppleConfigProfile{Name: "Name2", Identifier: "Identifier2", Mobileconfig: []byte("profile2-bytes")})
require.NoError(t, err)
profiles, err := ds.ListMDMAppleConfigProfiles(ctx, ptr.Uint(0))
require.NoError(t, err)
require.Len(t, profiles, 3)
h0, err := ds.NewHost(ctx, &fleet.Host{
DetailUpdatedAt: time.Now(),
LabelUpdatedAt: time.Now(),
PolicyUpdatedAt: time.Now(),
SeenTime: time.Now(),
OsqueryHostID: ptr.String("host0-osquery-id"),
NodeKey: ptr.String("host0-node-key"),
UUID: "host0-test-mdm-profiles",
Hostname: "hostname0",
})
require.NoError(t, err)
gotHost, err := ds.Host(ctx, h0.ID)
require.NoError(t, err)
require.Nil(t, gotHost.MDM.Profiles)
gotProfs, err := ds.GetHostMDMProfiles(ctx, h0.UUID)
require.NoError(t, err)
require.Nil(t, gotProfs)
h1, err := ds.NewHost(ctx, &fleet.Host{
DetailUpdatedAt: time.Now(),
LabelUpdatedAt: time.Now(),
PolicyUpdatedAt: time.Now(),
SeenTime: time.Now(),
OsqueryHostID: ptr.String("host1-osquery-id"),
NodeKey: ptr.String("host1-node-key"),
UUID: "host1-test-mdm-profiles",
Hostname: "hostname1",
})
require.NoError(t, err)
gotHost, err = ds.Host(ctx, h1.ID)
require.NoError(t, err)
require.Nil(t, gotHost.MDM.Profiles)
gotProfs, err = ds.GetHostMDMProfiles(ctx, h1.UUID)
require.NoError(t, err)
require.Nil(t, gotProfs)
expectedProfiles0 := map[uint]fleet.HostMDMAppleProfile{
p0.ProfileID: {HostUUID: h0.UUID, ProfileID: p0.ProfileID, CommandUUID: "cmd0-uuid", Status: &fleet.MDMAppleDeliveryPending, OperationType: fleet.MDMAppleOperationTypeInstall, Detail: ""},
p1.ProfileID: {HostUUID: h0.UUID, ProfileID: p1.ProfileID, CommandUUID: "cmd1-uuid", Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeInstall, Detail: ""},
p2.ProfileID: {HostUUID: h0.UUID, ProfileID: p2.ProfileID, CommandUUID: "cmd2-uuid", Status: &fleet.MDMAppleDeliveryFailed, OperationType: fleet.MDMAppleOperationTypeRemove, Detail: "Error removing profile"},
}
expectedProfiles1 := map[uint]fleet.HostMDMAppleProfile{
p0.ProfileID: {HostUUID: h1.UUID, ProfileID: p0.ProfileID, CommandUUID: "cmd0-uuid", Status: &fleet.MDMAppleDeliveryFailed, OperationType: fleet.MDMAppleOperationTypeInstall, Detail: "Error installing profile"},
p1.ProfileID: {HostUUID: h1.UUID, ProfileID: p1.ProfileID, CommandUUID: "cmd1-uuid", Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeInstall, Detail: ""},
p2.ProfileID: {HostUUID: h1.UUID, ProfileID: p2.ProfileID, CommandUUID: "cmd2-uuid", Status: &fleet.MDMAppleDeliveryFailed, OperationType: fleet.MDMAppleOperationTypeRemove, Detail: "Error removing profile"},
}
var args []interface{}
for _, p := range expectedProfiles0 {
args = append(args, p.HostUUID, p.ProfileID, p.CommandUUID, *p.Status, p.OperationType, p.Detail)
}
for _, p := range expectedProfiles1 {
args = append(args, p.HostUUID, p.ProfileID, p.CommandUUID, *p.Status, p.OperationType, p.Detail)
}
ExecAdhocSQL(t, ds, func(q sqlx.ExtContext) error {
_, err := q.ExecContext(ctx, `
INSERT INTO host_mdm_apple_profiles (
host_uuid, profile_id, command_uuid, status, operation_type, detail)
VALUES (?,?,?,?,?,?),(?,?,?,?,?,?),(?,?,?,?,?,?),(?,?,?,?,?,?),(?,?,?,?,?,?),(?,?,?,?,?,?)
`, args...,
)
if err != nil {
return err
}
return nil
})
gotHost, err = ds.Host(ctx, h1.ID)
require.NoError(t, err)
require.Nil(t, gotHost.MDM.Profiles) // ds.Host never returns MDM profiles
gotProfs, err = ds.GetHostMDMProfiles(ctx, h0.UUID)
require.NoError(t, err)
require.Len(t, gotProfs, 3)
for _, gp := range gotProfs {
ep, ok := expectedProfiles0[gp.ProfileID]
require.True(t, ok)
require.Equal(t, *ep.Status, *gp.Status)
require.Equal(t, ep.OperationType, gp.OperationType)
require.Equal(t, ep.Detail, gp.Detail)
}
gotHost, err = ds.Host(ctx, h1.ID)
require.NoError(t, err)
require.Nil(t, gotHost.MDM.Profiles) // ds.Host never returns MDM profiles
gotProfs, err = ds.GetHostMDMProfiles(ctx, h1.UUID)
require.NoError(t, err)
require.Len(t, gotProfs, 3)
for _, gp := range gotProfs {
ep, ok := expectedProfiles1[gp.ProfileID]
require.True(t, ok)
require.Equal(t, *ep.Status, *gp.Status)
require.Equal(t, ep.OperationType, gp.OperationType)
require.Equal(t, ep.Detail, gp.Detail)
}
}
func TestIngestMDMAppleDevicesFromDEPSync(t *testing.T) {
ds := CreateMySQLDS(t)
ctx := context.Background()
@@ -823,7 +942,6 @@ func testMDMAppleProfileManagement(t *testing.T, ds *Datastore) {
{ProfileID: globalPfs[1].ProfileID, ProfileIdentifier: globalPfs[1].Identifier, HostUUID: "test-uuid-1"},
{ProfileID: globalPfs[2].ProfileID, ProfileIdentifier: globalPfs[2].Identifier, HostUUID: "test-uuid-1"},
}, toRemove)
}
// checkMDMHostRelatedTables checks that rows are inserted for new MDM hosts in
+2 -2
View File
@@ -476,6 +476,8 @@ LIMIT
return &host, nil
}
// hostMDMSelect is the SQL fragment used to construct the JSON object
// of MDM host data.
const hostMDMSelect = `,
JSON_OBJECT(
'enrollment_status',
@@ -2359,7 +2361,6 @@ func (ds *Datastore) SetOrUpdateHostDiskEncryptionKey(ctx context.Context, hostI
base64_encrypted = VALUES(base64_encrypted)
`, hostID, encryptedBase64Key)
return err
}
func (ds *Datastore) GetUnverifiedDiskEncryptionKeys(ctx context.Context) ([]fleet.HostDiskEncryptionKey, error) {
@@ -2406,7 +2407,6 @@ func (ds *Datastore) GetHostDiskEncryptionKey(ctx context.Context, hostID uint)
FROM
host_disk_encryption_keys
WHERE host_id = ?`, hostID)
if err != nil {
if err == sql.ErrNoRows {
msg := fmt.Sprintf("for host %d", hostID)
+6 -6
View File
@@ -422,12 +422,12 @@ func (cp MDMAppleConfigProfile) ScreenPayloadTypes() error {
// HostMDMAppleProfile represents the status of an Apple MDM profile in a host.
type HostMDMAppleProfile struct {
HostUUID string
CommandUUID string
ProfileID uint
Status *MDMAppleDeliveryStatus
OperationType MDMAppleOperationType
Detail string
HostUUID string `db:"host_uuid" json:"-"`
CommandUUID string `db:"command_uuid" json:"-"`
ProfileID uint `db:"profile_id" json:"profile_id"`
Status *MDMAppleDeliveryStatus `db:"status" json:"status"`
OperationType MDMAppleOperationType `db:"operation_type" json:"operation_type"`
Detail string `db:"detail" json:"detail"`
}
type MDMAppleProfilePayload struct {
+3
View File
@@ -716,6 +716,9 @@ type Datastore interface {
// profile id.
DeleteMDMAppleConfigProfile(ctx context.Context, profileID uint) error
// GetHostMDMProfiles returns the MDM profile information for the specified host UUID.
GetHostMDMProfiles(ctx context.Context, hostUUID string) ([]HostMDMAppleProfile, error)
// NewMDMAppleEnrollmentProfile creates and returns new enrollment profile.
// Such enrollment profiles allow devices to enroll to Fleet MDM.
NewMDMAppleEnrollmentProfile(ctx context.Context, enrollmentPayload MDMAppleEnrollmentProfilePayload) (*MDMAppleEnrollmentProfile, error)
+9 -1
View File
@@ -223,6 +223,14 @@ type MDMHostData struct {
// EncryptionKeyAvailable indicates if Fleet was able to retrieve and
// decode an encryption key for the host.
EncryptionKeyAvailable bool `json:"encryption_key_available" db:"-" csv:"-"`
// Profiles is a list of HostMDMProfiles for the host. Note that as for many
// other host fields, it is not filled in by all host-returning datastore methods.
//
// It is a pointer to a slice so that when set, it gets marhsaled even
// if the slice is empty, but when unset, it doesn't get marshaled
// (e.g. we don't return that information for the List Hosts endpoint).
Profiles *[]HostMDMAppleProfile `json:"profiles,omitempty" db:"profiles" csv:"-"`
}
// Scan implements the Scanner interface for sqlx, to support unmarshaling a
@@ -268,7 +276,7 @@ func (h Host) AuthzType() string {
}
// HostDetail provides the full host metadata along with associated labels and
// packs.
// packs. It also includes policies, batteries, and MDM profiles, as applicable.
type HostDetail struct {
Host
// Labels is the list of labels the host is a member of.
+10
View File
@@ -513,6 +513,8 @@ type ListMDMAppleConfigProfilesFunc func(ctx context.Context, teamID *uint) ([]*
type DeleteMDMAppleConfigProfileFunc func(ctx context.Context, profileID uint) error
type GetHostMDMProfilesFunc func(ctx context.Context, hostUUID string) ([]fleet.HostMDMAppleProfile, error)
type NewMDMAppleEnrollmentProfileFunc func(ctx context.Context, enrollmentPayload fleet.MDMAppleEnrollmentProfilePayload) (*fleet.MDMAppleEnrollmentProfile, error)
type GetMDMAppleEnrollmentProfileByTokenFunc func(ctx context.Context, token string) (*fleet.MDMAppleEnrollmentProfile, error)
@@ -1307,6 +1309,9 @@ type DataStore struct {
DeleteMDMAppleConfigProfileFunc DeleteMDMAppleConfigProfileFunc
DeleteMDMAppleConfigProfileFuncInvoked bool
GetHostMDMProfilesFunc GetHostMDMProfilesFunc
GetHostMDMProfilesFuncInvoked bool
NewMDMAppleEnrollmentProfileFunc NewMDMAppleEnrollmentProfileFunc
NewMDMAppleEnrollmentProfileFuncInvoked bool
@@ -3122,6 +3127,11 @@ func (s *DataStore) DeleteMDMAppleConfigProfile(ctx context.Context, profileID u
return s.DeleteMDMAppleConfigProfileFunc(ctx, profileID)
}
func (s *DataStore) GetHostMDMProfiles(ctx context.Context, hostUUID string) ([]fleet.HostMDMAppleProfile, error) {
s.GetHostMDMProfilesFuncInvoked = true
return s.GetHostMDMProfilesFunc(ctx, hostUUID)
}
func (s *DataStore) NewMDMAppleEnrollmentProfile(ctx context.Context, enrollmentPayload fleet.MDMAppleEnrollmentProfilePayload) (*fleet.MDMAppleEnrollmentProfile, error) {
s.mu.Lock()
s.NewMDMAppleEnrollmentProfileFuncInvoked = true
-2
View File
@@ -367,7 +367,6 @@ func (svc *Service) ListMDMAppleConfigProfiles(ctx context.Context, teamID uint)
return nil, ctxerr.Wrap(ctx, err)
}
// TODO: record activitiy
return cps, nil
}
@@ -432,7 +431,6 @@ func (svc *Service) GetMDMAppleConfigProfile(ctx context.Context, profileID uint
return nil, err
}
// TODO: record activitiy
return cp, nil
}
+137 -3
View File
@@ -467,6 +467,143 @@ func mcBytesForTest(name, identifier, uuid string) []byte {
`, name, identifier, uuid))
}
func TestHostDetailsMDMProfiles(t *testing.T) {
svc, ctx, ds := setupAppleMDMService(t)
ctx = viewer.NewContext(ctx, viewer.Viewer{User: &fleet.User{GlobalRole: ptr.String(fleet.RoleAdmin)}})
expected := []fleet.HostMDMAppleProfile{
{HostUUID: "H057-UU1D-1337", ProfileID: uint(5), CommandUUID: "CMD-UU1D-5", Status: &fleet.MDMAppleDeliveryPending, OperationType: fleet.MDMAppleOperationTypeInstall, Detail: ""},
{HostUUID: "H057-UU1D-1337", ProfileID: uint(8), CommandUUID: "CMD-UU1D-8", Status: &fleet.MDMAppleDeliveryApplied, OperationType: fleet.MDMAppleOperationTypeInstall, Detail: ""},
{HostUUID: "H057-UU1D-1337", ProfileID: uint(13), CommandUUID: "CMD-UU1D-13", Status: &fleet.MDMAppleDeliveryFailed, OperationType: fleet.MDMAppleOperationTypeRemove, Detail: "Error removing profile"},
}
expectedByProfileID := make(map[uint]fleet.HostMDMAppleProfile)
for _, ep := range expected {
expectedByProfileID[ep.ProfileID] = ep
}
ds.GetHostMDMProfilesFunc = func(ctx context.Context, hostUUID string) ([]fleet.HostMDMAppleProfile, error) {
if hostUUID == "H057-UU1D-1337" {
return expected, nil
}
return []fleet.HostMDMAppleProfile{}, nil
}
ds.HostFunc = func(ctx context.Context, hostID uint) (*fleet.Host, error) {
if hostID == uint(42) {
return &fleet.Host{ID: uint(42), UUID: "H057-UU1D-1337"}, nil
}
return &fleet.Host{ID: hostID, UUID: "WR0N6-UU1D"}, nil
}
ds.HostByIdentifierFunc = func(ctx context.Context, identifier string) (*fleet.Host, error) {
if identifier == "h0571d3n71f13r" {
return &fleet.Host{ID: uint(42), UUID: "H057-UU1D-1337"}, nil
}
return &fleet.Host{ID: uint(21), UUID: "WR0N6-UU1D"}, nil
}
ds.LoadHostSoftwareFunc = func(ctx context.Context, host *fleet.Host, includeCVEScores bool) error {
return nil
}
ds.ListLabelsForHostFunc = func(ctx context.Context, hid uint) ([]*fleet.Label, error) {
return nil, nil
}
ds.ListPacksForHostFunc = func(ctx context.Context, hid uint) (packs []*fleet.Pack, err error) {
return nil, nil
}
ds.ListHostBatteriesFunc = func(ctx context.Context, id uint) ([]*fleet.HostBattery, error) {
return nil, nil
}
ds.ListPoliciesForHostFunc = func(ctx context.Context, host *fleet.Host) ([]*fleet.HostPolicy, error) {
return nil, nil
}
cases := []struct {
name string
mdmEnabled bool
hostID *uint
hostIdentifier *string
expected *[]fleet.HostMDMAppleProfile
}{
{
name: "TestGetHostMDMProfilesOK",
mdmEnabled: true,
hostID: ptr.Uint(42),
hostIdentifier: nil,
expected: &expected,
},
{
name: "TestGetHostMDMProfilesEmpty",
mdmEnabled: false,
hostID: ptr.Uint(21),
hostIdentifier: nil,
expected: &[]fleet.HostMDMAppleProfile{},
},
{
name: "TestGetHostMDMProfilesNil",
mdmEnabled: false,
hostID: ptr.Uint(42),
hostIdentifier: nil,
expected: nil,
},
{
name: "TestHostByIdentifierMDMProfilesOK",
mdmEnabled: true,
hostID: nil,
hostIdentifier: ptr.String("h0571d3n71f13r"),
expected: &expected,
},
{
name: "TestHostByIdentifierMDMProfilesNil",
mdmEnabled: false,
hostID: nil,
hostIdentifier: ptr.String("h0571d3n71f13r"),
expected: nil,
},
{
name: "TestHostByIdentifierMDMProfilesEmpty",
mdmEnabled: false,
hostID: nil,
hostIdentifier: ptr.String("4n07h3r1d3n71f13r"),
expected: &[]fleet.HostMDMAppleProfile{},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
ds.AppConfigFunc = func(context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{MDM: fleet.MDM{EnabledAndConfigured: c.mdmEnabled}}, nil
}
ds.AppConfigFuncInvoked = false
ds.HostFuncInvoked = false
ds.HostByIdentifierFuncInvoked = false
ds.GetHostMDMProfilesFuncInvoked = false
var gotHost *fleet.HostDetail
if c.hostID != nil {
h, err := svc.GetHost(ctx, *c.hostID, fleet.HostDetailOptions{})
require.NoError(t, err)
require.True(t, ds.HostFuncInvoked)
gotHost = h
}
if c.hostIdentifier != nil {
h, err := svc.HostByIdentifier(ctx, *c.hostIdentifier, fleet.HostDetailOptions{})
require.NoError(t, err)
require.True(t, ds.HostByIdentifierFuncInvoked)
gotHost = h
}
require.NotNil(t, gotHost)
require.True(t, ds.AppConfigFuncInvoked)
if !c.mdmEnabled {
require.Nil(t, gotHost.MDM.Profiles)
return
}
require.True(t, ds.GetHostMDMProfilesFuncInvoked)
require.NotNil(t, gotHost.MDM.Profiles)
require.ElementsMatch(t, *c.expected, *gotHost.MDM.Profiles)
})
}
}
func TestAppleMDMEnrollmentProfile(t *testing.T) {
svc, ctx, _ := setupAppleMDMService(t)
@@ -801,7 +938,6 @@ func TestMDMCommandAndReportResultsProfileHandling(t *testing.T) {
require.True(t, ds.GetMDMAppleCommandRequestTypeFuncInvoked)
require.True(t, ds.UpdateHostMDMAppleProfileFuncInvoked)
}
}
func TestMDMBatchSetAppleProfiles(t *testing.T) {
@@ -1079,7 +1215,6 @@ func TestMDMAppleCommander(t *testing.T) {
pushes := make(map[string]*mdm.Push, len(targetUUIDs))
for _, uuid := range targetUUIDs {
pushes[uuid] = &mdm.Push{
PushMagic: "magic" + uuid,
Token: []byte("token" + uuid),
Topic: "topic" + uuid,
@@ -1240,7 +1375,6 @@ func TestMDMAppleReconcileProfiles(t *testing.T) {
require.True(t, ds.ListMDMAppleProfilesToRemoveFuncInvoked)
require.True(t, ds.GetMDMAppleProfilesContentsFuncInvoked)
require.True(t, ds.BulkUpsertMDMAppleHostProfilesFuncInvoked)
}
func mobileconfigForTest(name, identifier string) []byte {
+13
View File
@@ -795,6 +795,19 @@ func (svc *Service) getHostDetails(ctx context.Context, host *fleet.Host, opts f
policies = &hp
}
// If Fleet MDM is enabled and configured, we want to include MDM profiles.
ac, err := svc.ds.AppConfig(ctx)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "get app config for host mdm profiles")
}
if ac.MDM.EnabledAndConfigured {
profiles, err := svc.ds.GetHostMDMProfiles(ctx, host.UUID)
if err != nil {
return nil, ctxerr.Wrap(ctx, err, "get host mdm profiles")
}
host.MDM.Profiles = &profiles
}
return &fleet.HostDetail{
Host: *host,
Labels: labels,
+7
View File
@@ -37,6 +37,9 @@ func TestHostDetails(t *testing.T) {
Description: "the foobar label",
},
}
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{}, nil
}
ds.ListLabelsForHostFunc = func(ctx context.Context, hid uint) ([]*fleet.Label, error) {
return expectedLabels, nil
}
@@ -83,6 +86,10 @@ func TestHostAuth(t *testing.T) {
teamHost := &fleet.Host{TeamID: ptr.Uint(1)}
globalHost := &fleet.Host{}
ds.AppConfigFunc = func(ctx context.Context) (*fleet.AppConfig, error) {
return &fleet.AppConfig{}, nil
}
ds.DeleteHostFunc = func(ctx context.Context, hid uint) error {
return nil
}