Apply custom setup assistants (if present) when ingesting new devices (#11563)

This commit is contained in:
Martin Angers
2023-05-09 13:00:18 -04:00
committed by GitHub
parent 487f8b6e1f
commit 70f18dda4a
18 changed files with 423 additions and 327 deletions
+36 -9
View File
@@ -252,7 +252,7 @@ ORDER BY created_at DESC
func (ds *Datastore) GetMDMAppleEnrollmentProfileByToken(ctx context.Context, token string) (*fleet.MDMAppleEnrollmentProfile, error) {
var enrollment fleet.MDMAppleEnrollmentProfile
if err := sqlx.GetContext(ctx, ds.writer,
if err := sqlx.GetContext(ctx, ds.reader,
&enrollment,
`
SELECT
@@ -277,6 +277,33 @@ WHERE
return &enrollment, nil
}
func (ds *Datastore) GetMDMAppleEnrollmentProfileByType(ctx context.Context, typ fleet.MDMAppleEnrollmentType) (*fleet.MDMAppleEnrollmentProfile, error) {
var enrollment fleet.MDMAppleEnrollmentProfile
if err := sqlx.GetContext(ctx, ds.writer, // use writer as it is used just after creation in some cases
&enrollment,
`
SELECT
id,
token,
type,
dep_profile,
created_at,
updated_at
FROM
mdm_apple_enrollment_profiles
WHERE
type = ?
`,
typ,
); err != nil {
if err == sql.ErrNoRows {
return nil, ctxerr.Wrap(ctx, notFound("MDMAppleEnrollmentProfile"))
}
return nil, ctxerr.Wrap(ctx, err, "get enrollment profile by type")
}
return &enrollment, nil
}
func (ds *Datastore) GetMDMAppleCommandRequestType(ctx context.Context, commandUUID string) (string, error) {
var rt string
err := sqlx.GetContext(ctx, ds.reader, &rt, `SELECT request_type FROM nano_commands WHERE command_uuid = ?`, commandUUID)
@@ -599,20 +626,20 @@ func insertMDMAppleHostDB(
return nil
}
func (ds *Datastore) IngestMDMAppleDevicesFromDEPSync(ctx context.Context, devices []godep.Device) (int64, error) {
func (ds *Datastore) IngestMDMAppleDevicesFromDEPSync(ctx context.Context, devices []godep.Device) (createdCount int64, teamID *uint, err error) {
if len(devices) < 1 {
level.Debug(ds.logger).Log("msg", "ingesting devices from DEP received < 1 device, skipping", "len(devices)", len(devices))
return 0, nil
return 0, nil, nil
}
filteredDevices := filterMDMAppleDevices(devices, ds.logger)
if len(filteredDevices) < 1 {
level.Debug(ds.logger).Log("msg", "ingesting devices from DEP filtered all devices, skipping", "len(devices)", len(devices))
return 0, nil
return 0, nil, nil
}
appCfg, err := ds.AppConfig(ctx)
if err != nil {
return 0, ctxerr.Wrap(ctx, err, "ingest mdm apple host get app config")
return 0, nil, ctxerr.Wrap(ctx, err, "ingest mdm apple host get app config")
}
args := []interface{}{nil}
@@ -629,13 +656,13 @@ func (ds *Datastore) IngestMDMAppleDevicesFromDEPSync(ctx context.Context, devic
// If the team doesn't exist, we still ingest the device, but it won't
// belong to any team.
case err != nil:
return 0, ctxerr.Wrap(ctx, err, "ingest mdm apple host get team by name")
return 0, nil, ctxerr.Wrap(ctx, err, "ingest mdm apple host get team by name")
default:
args[0] = team.ID
teamID = &team.ID
}
}
var resCount int64
err = ds.withRetryTxx(ctx, func(tx sqlx.ExtContext) error {
us, unionArgs := unionSelectDevices(filteredDevices)
args = append(args, unionArgs...)
@@ -678,7 +705,7 @@ func (ds *Datastore) IngestMDMAppleDevicesFromDEPSync(ctx context.Context, devic
if err != nil {
return ctxerr.Wrap(ctx, err, "ingest mdm apple hosts from dep sync rows affected")
}
resCount = n
createdCount = n
// get new host ids
args = []interface{}{}
@@ -715,7 +742,7 @@ func (ds *Datastore) IngestMDMAppleDevicesFromDEPSync(ctx context.Context, devic
return nil
})
return resCount, err
return createdCount, teamID, err
}
func upsertMDMAppleHostDisplayNamesDB(ctx context.Context, tx sqlx.ExtContext, hosts ...fleet.Host) error {
+67 -6
View File
@@ -56,6 +56,7 @@ func TestMDMApple(t *testing.T) {
{"TestListMDMAppleCommands", testListMDMAppleCommands},
{"TestMDMAppleEULA", testMDMAppleEULA},
{"TestMDMAppleSetupAssistant", testMDMAppleSetupAssistant},
{"TestMDMAppleEnrollmentProfile", testMDMAppleEnrollmentProfile},
}
for _, c := range cases {
@@ -443,9 +444,10 @@ func TestIngestMDMAppleDevicesFromDEPSync(t *testing.T) {
}
wantSerials = append(wantSerials, "abc", "xyz", "ijk")
n, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
n, tmID, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
require.NoError(t, err)
require.Equal(t, int64(3), n) // 3 new hosts ("abc", "xyz", "ijk")
require.Nil(t, tmID)
hosts = listHostsCheckCount(t, ds, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}, len(wantSerials))
gotSerials := []string{}
@@ -468,8 +470,9 @@ func TestDEPSyncTeamAssignment(t *testing.T) {
{SerialNumber: "def", Model: "MacBook Pro", OS: "OSX", OpType: "added"},
}
n, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
n, tmID, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
require.NoError(t, err)
require.Nil(t, tmID)
require.Equal(t, int64(2), n)
hosts := listHostsCheckCount(t, ds, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}, 2)
@@ -493,9 +496,11 @@ func TestDEPSyncTeamAssignment(t *testing.T) {
{SerialNumber: "xyz", Model: "MacBook Pro", OS: "OSX", OpType: "added"},
}
n, err = ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
n, tmID, err = ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
require.NoError(t, err)
require.Equal(t, int64(1), n)
require.NotNil(t, tmID)
require.Equal(t, team.ID, *tmID)
hosts = listHostsCheckCount(t, ds, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}, 3)
for _, h := range hosts {
@@ -514,9 +519,10 @@ func TestDEPSyncTeamAssignment(t *testing.T) {
{SerialNumber: "jqk", Model: "MacBook Pro", OS: "OSX", OpType: "added"},
}
n, err = ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
n, tmID, err = ds.IngestMDMAppleDevicesFromDEPSync(ctx, depDevices)
require.NoError(t, err)
require.EqualValues(t, n, 1)
require.Nil(t, tmID)
hosts = listHostsCheckCount(t, ds, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}, 4)
for _, h := range hosts {
@@ -638,11 +644,12 @@ func testIngestMDMAppleIngestAfterDEPSync(t *testing.T, ds *Datastore) {
testModel := "MacBook Pro"
// simulate a host that is first ingested via DEP (e.g., the device was added via Apple Business Manager)
n, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
n, tmID, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
{SerialNumber: testSerial, Model: testModel, OS: "OSX", OpType: "added"},
})
require.NoError(t, err)
require.Equal(t, int64(1), n)
require.Nil(t, tmID)
hosts := listHostsCheckCount(t, ds, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}, 1)
// hosts that are first ingested via DEP will have a serial number but not a UUID because UUID
@@ -684,11 +691,12 @@ func testIngestMDMAppleCheckinBeforeDEPSync(t *testing.T, ds *Datastore) {
checkMDMHostRelatedTables(t, ds, hosts[0].ID, testSerial, testModel)
// no effect if same host appears in DEP sync
n, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
n, tmID, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
{SerialNumber: testSerial, Model: testModel, OS: "OSX", OpType: "added"},
})
require.NoError(t, err)
require.Equal(t, int64(0), n)
require.Nil(t, tmID)
hosts = listHostsCheckCount(t, ds, fleet.TeamFilter{User: test.UserAdmin}, fleet.HostListOptions{}, 1)
require.Equal(t, testSerial, hosts[0].HardwareSerial)
@@ -3407,3 +3415,56 @@ func testMDMAppleSetupAssistant(t *testing.T, ds *Datastore) {
err = ds.DeleteMDMAppleSetupAssistant(ctx, &tm.ID)
require.NoError(t, err)
}
func testMDMAppleEnrollmentProfile(t *testing.T, ds *Datastore) {
ctx := context.Background()
_, err := ds.GetMDMAppleEnrollmentProfileByType(ctx, fleet.MDMAppleEnrollmentTypeAutomatic)
require.Error(t, err)
require.ErrorIs(t, err, sql.ErrNoRows)
_, err = ds.GetMDMAppleEnrollmentProfileByToken(ctx, "abcd")
require.Error(t, err)
require.ErrorIs(t, err, sql.ErrNoRows)
// add a new automatic enrollment profile
rawMsg := json.RawMessage(`{"allow_pairing": true}`)
profAuto, err := ds.NewMDMAppleEnrollmentProfile(ctx, fleet.MDMAppleEnrollmentProfilePayload{
Type: "automatic",
DEPProfile: &rawMsg,
Token: "abcd",
})
require.NoError(t, err)
require.NotZero(t, profAuto.ID)
// add a new manual enrollment profile
profMan, err := ds.NewMDMAppleEnrollmentProfile(ctx, fleet.MDMAppleEnrollmentProfilePayload{
Type: "manual",
DEPProfile: &rawMsg,
Token: "efgh",
})
require.NoError(t, err)
require.NotZero(t, profMan.ID)
profs, err := ds.ListMDMAppleEnrollmentProfiles(ctx)
require.NoError(t, err)
require.Len(t, profs, 2)
tokens := make([]string, 2)
for i, p := range profs {
tokens[i] = p.Token
}
require.ElementsMatch(t, []string{"abcd", "efgh"}, tokens)
// get the automatic profile by type
getProf, err := ds.GetMDMAppleEnrollmentProfileByType(ctx, fleet.MDMAppleEnrollmentTypeAutomatic)
require.NoError(t, err)
getProf.UpdateCreateTimestamps = fleet.UpdateCreateTimestamps{}
require.Equal(t, profAuto, getProf)
// get the manual profile by token
getProf, err = ds.GetMDMAppleEnrollmentProfileByToken(ctx, "efgh")
require.NoError(t, err)
getProf.UpdateCreateTimestamps = fleet.UpdateCreateTimestamps{}
require.Equal(t, profMan, getProf)
}
+2 -1
View File
@@ -1098,11 +1098,12 @@ func testHostsListMDM(t *testing.T, ds *Datastore) {
}
// enrollment: pending (with Fleet mdm)
n, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
n, tmID, err := ds.IngestMDMAppleDevicesFromDEPSync(ctx, []godep.Device{
{SerialNumber: "532141num832", Model: "MacBook Pro", OS: "OSX", OpType: "added"},
})
require.NoError(t, err)
require.Equal(t, int64(1), n)
require.Nil(t, tmID)
const simpleMDM, kandji, unknown = "https://simplemdm.com", "https://kandji.io", "https://url.com"
err = ds.SetOrUpdateMDMData(ctx, hostIDs[0], false, true, simpleMDM, true, fleet.WellKnownMDMSimpleMDM) // enrollment: automatic