fix various bugs after testing windows MDM profiles (#15264)
for #13281
This commit is contained in:
+1
-1
@@ -43,7 +43,7 @@ const DeleteProfileModal = ({
|
||||
<p>
|
||||
This action will delete configuration profile{" "}
|
||||
<span className={`${baseClass}__profile-name`}>{profileName}</span>{" "}
|
||||
from all macOS hosts{messageSuffix}.
|
||||
from all hosts{messageSuffix}.
|
||||
</p>
|
||||
<div className="modal-cta-wrap">
|
||||
<Button
|
||||
|
||||
+20
-13
@@ -98,21 +98,28 @@ const tableHeaders: IDataColumn[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const makeWindowsRows = ({ os_settings }: IHostMdmData) => {
|
||||
if (
|
||||
!os_settings?.disk_encryption?.status ||
|
||||
!isWindowsDiskEncryptionStatus(os_settings.disk_encryption.status)
|
||||
) {
|
||||
return null;
|
||||
const makeWindowsRows = ({ profiles, os_settings }: IHostMdmData) => {
|
||||
const rows: ITableRowOsSettings[] = [];
|
||||
|
||||
if (profiles) {
|
||||
rows.push(...profiles);
|
||||
}
|
||||
|
||||
const rows: ITableRowOsSettings[] = [];
|
||||
rows.push(
|
||||
generateWinDiskEncryptionProfile(
|
||||
os_settings.disk_encryption.status,
|
||||
os_settings.disk_encryption.detail
|
||||
)
|
||||
);
|
||||
if (
|
||||
os_settings?.disk_encryption?.status &&
|
||||
isWindowsDiskEncryptionStatus(os_settings.disk_encryption.status)
|
||||
) {
|
||||
rows.push(
|
||||
generateWinDiskEncryptionProfile(
|
||||
os_settings.disk_encryption.status,
|
||||
os_settings.disk_encryption.detail
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (rows.length === 0 && !profiles) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
+7
-4
@@ -45,12 +45,15 @@ func GroupFromBytes(b []byte) (*Group, error) {
|
||||
return nil, fmt.Errorf("failed to unmarshal spec item %w: \n%s", err, specItem)
|
||||
}
|
||||
|
||||
if s.Spec == nil {
|
||||
return nil, fmt.Errorf("no spec field on %q document", s.Kind)
|
||||
}
|
||||
|
||||
kind := strings.ToLower(s.Kind)
|
||||
|
||||
if s.Spec == nil {
|
||||
if kind == "" {
|
||||
return nil, errors.New(`Missing required fields ("spec", "kind") on provided configuration.`)
|
||||
}
|
||||
return nil, fmt.Errorf(`Missing required fields ("spec") on provided %q configuration.`, s.Kind)
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case fleet.QueryKind:
|
||||
var querySpec *fleet.QuerySpec
|
||||
|
||||
@@ -69,3 +69,45 @@ func TestGroupFromBytesWithWin10CISQueries(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, g.Policies)
|
||||
}
|
||||
|
||||
func TestGroupFromBytesMissingFields(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in []byte
|
||||
want string
|
||||
}{
|
||||
{
|
||||
"missing spec",
|
||||
[]byte(`
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: team
|
||||
`),
|
||||
`Missing required fields ("spec") on provided "team" configuration.`,
|
||||
},
|
||||
{
|
||||
"missing spec and kind",
|
||||
[]byte(`
|
||||
---
|
||||
apiVersion: v1
|
||||
`),
|
||||
`Missing required fields ("spec", "kind") on provided configuration`,
|
||||
},
|
||||
{
|
||||
"missing spec and empty string kind",
|
||||
[]byte(`
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ""
|
||||
`),
|
||||
`Missing required fields ("spec", "kind") on provided configuration`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := GroupFromBytes(tt.in)
|
||||
require.ErrorContains(t, err, tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ func updateMDMWindowsHostProfileStatusFromResponseDB(
|
||||
// update their detail and status.
|
||||
const updateHostProfilesStmt = `
|
||||
INSERT INTO host_mdm_windows_profiles
|
||||
(host_uuid, profile_uuid, detail, status)
|
||||
(host_uuid, profile_uuid, detail, status, command_uuid)
|
||||
VALUES %s
|
||||
ON DUPLICATE KEY UPDATE
|
||||
detail = VALUES(detail),
|
||||
@@ -402,11 +402,11 @@ func updateMDMWindowsHostProfileStatusFromResponseDB(
|
||||
// find the matching entries for the given host_uuid, command_uuid combinations.
|
||||
stmt, args, err := sqlx.In(getMatchingHostProfilesStmt, hostUUID, commandUUIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
return ctxerr.Wrap(ctx, err, "building sqlx.In query")
|
||||
}
|
||||
var matchingHostProfiles []fleet.MDMWindowsProfilePayload
|
||||
if err := sqlx.SelectContext(ctx, tx, &matchingHostProfiles, stmt, args...); err != nil {
|
||||
return err
|
||||
return ctxerr.Wrap(ctx, err, "running query to get matching profiles")
|
||||
}
|
||||
|
||||
// batch-update the matching entries with the desired detail and status>
|
||||
@@ -415,12 +415,12 @@ func updateMDMWindowsHostProfileStatusFromResponseDB(
|
||||
for _, hp := range matchingHostProfiles {
|
||||
payload := uuidsToPayloads[hp.CommandUUID]
|
||||
args = append(args, hp.HostUUID, hp.ProfileUUID, payload.Detail, payload.Status)
|
||||
sb.WriteString("(?, ?, ?, ?),")
|
||||
sb.WriteString("(?, ?, ?, ?, command_uuid),")
|
||||
}
|
||||
|
||||
stmt = fmt.Sprintf(updateHostProfilesStmt, strings.TrimSuffix(sb.String(), ","))
|
||||
_, err = tx.ExecContext(ctx, stmt, args...)
|
||||
return err
|
||||
return ctxerr.Wrap(ctx, err, "updating host profiles")
|
||||
}
|
||||
|
||||
func (ds *Datastore) GetMDMWindowsCommandResults(ctx context.Context, commandUUID string) ([]*fleet.MDMCommandResult, error) {
|
||||
|
||||
@@ -68,8 +68,7 @@ func (m *MDMWindowsConfigProfile) ValidateUserProvided() error {
|
||||
return errors.New("Only <Replace> supported as a top level element. Make sure you don't have other top level elements.")
|
||||
}
|
||||
|
||||
for _, target := range element.FindElements("Target") {
|
||||
locURI := target.FindElement("LocURI")
|
||||
for _, locURI := range element.FindElements("//Target/LocURI") {
|
||||
if locURI != nil {
|
||||
if err := validateFleetProvidedLocURI(locURI.Text()); err != nil {
|
||||
return err
|
||||
|
||||
@@ -40,6 +40,13 @@ func TestValidateUserProvided(t *testing.T) {
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "Reserved LocURI with implicit ./Device prefix",
|
||||
profile: MDMWindowsConfigProfile{
|
||||
SyncML: []byte(`<Replace><Target><LocURI>./Vendor/MSFT/BitLocker/Foo</LocURI></Target></Replace>`),
|
||||
},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "XML with Multiple Replace Elements",
|
||||
profile: MDMWindowsConfigProfile{
|
||||
|
||||
@@ -396,8 +396,8 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
FleetBitLockerTargetLocURI = "./Device/Vendor/MSFT/BitLocker"
|
||||
FleetOSUpdateTargetLocURI = "./Device/Vendor/MSFT/Policy/Config/Update"
|
||||
FleetBitLockerTargetLocURI = "/Vendor/MSFT/BitLocker"
|
||||
FleetOSUpdateTargetLocURI = "/Vendor/MSFT/Policy/Config/Update"
|
||||
)
|
||||
|
||||
func ResolveWindowsMDMDiscovery(serverURL string) (string, error) {
|
||||
|
||||
@@ -1120,8 +1120,10 @@ func (svc *Service) DeleteMDMWindowsConfigProfile(ctx context.Context, profileUU
|
||||
return ctxerr.Wrap(ctx, err)
|
||||
}
|
||||
|
||||
// TODO: integrate the call to bulk-update host profiles affected by this deletion (see Apple's implementation)
|
||||
// (part of https://github.com/fleetdm/fleet/issues/14364)
|
||||
// cannot use the profile ID as it is now deleted
|
||||
if err := svc.ds.BulkSetPendingMDMHostProfiles(ctx, nil, []uint{teamID}, nil, nil, nil); err != nil {
|
||||
return ctxerr.Wrap(ctx, err, "bulk set pending host profiles")
|
||||
}
|
||||
|
||||
var (
|
||||
actTeamID *uint
|
||||
|
||||
Reference in New Issue
Block a user