fleet/frontend/pages/hosts/details/OSSettingsModal/OSSettingsTable/OSSettingStatusCell/helpers.ts
Scott Gress 7a8f18cc8f
Implement BitLocker "action required" status (#31451)
for #31182 

# Details

This PR implements the "Action Required" state for Windows host disk
encryption. This includes updates to reporting for:

* disk encryption summary (`GET /fleet/disk_encryption`)
* config profiles summary (`GET /configuration_profiles/summary`)
* config profile status ( `GET
/configuration_profiles/{profile_uuid}/status`)

For disk encryption summary, the statuses are now determined according
to [the rules in the
Figma](https://www.figma.com/design/XbhlPuEJxQtOgTZW9EOJZp/-28133-Enforce-BitLocker-PIN?node-id=5484-928&t=JB13g8zQ2QDVEmPB-0).
TL;DR if the criteria for "verified" or "verifying" are set, but a
required PIN is not set, we report a host as "action required".

For profiles, I followed what seems to be the existing pattern and set
the profile status to "pending" if the disk encryption status is "action
required". This is what we do for hosts with the "enforcing" or
"removing enforcement" statuses.

A lot of the changes in these files are due to the creation of the
`fleet.DiskEncryptionConfig` struct to hold info about disk encryption
config, and passing variables of that type to various functions instead
of passing a `bool` to indicate whether encryption is enabled. Other
than that, the functional changes are constrained to a few files.

> Note: to get the "require bitlocker pin" UI, compile the front end
with:
```
SHOW_BITLOCKER_PIN_OPTION=true NODE_ENV=development yarn run webpack --progress --watch
```

# Checklist for submitter

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

- [ ] Changes file added for user-visible changes in `changes/`,
`orbit/changes/` or `ee/fleetd-chrome/changes`.
See [Changes
files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files)
for more information.
Changelog will be added when feature is complete.

- [X] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)

## Testing

- [X] Added/updated automated tests
- [X] Where appropriate, [automated tests simulate multiple hosts and
test for host
isolation](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/reference/patterns-backend.md#unit-testing)
(updates to one hosts's records do not affect another)

- [ ] QA'd all new/changed functionality manually
Could use some help testing this end-to-end. I was able to test the
banners showing up correctly, but testing the Disk Encryption table
requires some Windows-MDM-fu (I just get all zeroes).

## Database migrations

- [X] Checked table schema to confirm autoupdate
- [X] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [X] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [X] Ensured the correct collation is explicitly set for character
columns (`COLLATE utf8mb4_unicode_ci`).
2025-08-05 11:23:27 -05:00

167 lines
5.3 KiB
TypeScript

import {
FLEET_FILEVAULT_PROFILE_DISPLAY_NAME,
ProfileOperationType,
} from "interfaces/mdm";
import { IconNames } from "components/icons";
import {
TooltipInnerContentFunc,
TooltipInnerContentOption,
} from "./components/Tooltip/TooltipContent";
import { OsSettingsTableStatusValue } from "../OSSettingsTableConfig";
import TooltipInnerContentActionRequired from "./components/Tooltip/ActionRequired";
export const isDiskEncryptionProfile = (profileName: string) => {
return profileName === FLEET_FILEVAULT_PROFILE_DISPLAY_NAME;
};
export type ProfileDisplayOption = {
statusText: string;
iconName: IconNames;
tooltip: TooltipInnerContentOption | null;
} | null;
type OperationTypeOption = Record<
OsSettingsTableStatusValue,
ProfileDisplayOption
>;
type ProfileDisplayConfig = Record<ProfileOperationType, OperationTypeOption>;
// Profiles for iOS and iPadOS skip the verifying step
const APPLE_PROFILE_VERIFIED_DISPLAY_CONFIG: ProfileDisplayOption = {
statusText: "Verified",
iconName: "success",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The host turned disk encryption on and sent the key to Fleet. " +
"Fleet verified."
: "The host applied the setting. Fleet verified.",
} as const;
const MAC_PROFILE_VERIFYING_DISPLAY_CONFIG: ProfileDisplayOption = {
statusText: "Verifying",
iconName: "success-outline",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The host acknowledged the MDM command to turn on disk encryption. " +
"Fleet is verifying with osquery and retrieving the disk encryption key. " +
"This may take up to one hour."
: "The host acknowledged the MDM command to apply the setting. Fleet is " +
"verifying with osquery.",
} as const;
export const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
install: {
verified: APPLE_PROFILE_VERIFIED_DISPLAY_CONFIG,
success: APPLE_PROFILE_VERIFIED_DISPLAY_CONFIG,
verifying: MAC_PROFILE_VERIFYING_DISPLAY_CONFIG,
acknowledged: MAC_PROFILE_VERIFYING_DISPLAY_CONFIG,
pending: {
statusText: "Enforcing (pending)",
iconName: "pending-outline",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The hosts will receive the MDM command to turn on disk encryption " +
"when the hosts come online."
: "The host will receive the MDM command to apply the setting when the " +
"host comes online.",
},
action_required: {
statusText: "Action required (pending)",
iconName: "pending-outline",
tooltip: TooltipInnerContentActionRequired as TooltipInnerContentFunc,
},
failed: {
statusText: "Failed",
iconName: "error",
tooltip: null,
},
},
remove: {
pending: {
statusText: "Removing enforcement (pending)",
iconName: "pending-outline",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The host will receive the MDM command to remove the disk encryption profile when the " +
"host comes online."
: "The host will receive the MDM command to remove the setting when the host " +
"comes online.",
},
action_required: null, // should not be reached
verified: null, // should not be reached
verifying: null, // should not be reached
success: null, // should not be reached
acknowledged: null, // should not be reached
failed: {
statusText: "Failed",
iconName: "error",
tooltip: null,
},
},
};
type WindowsDiskEncryptionDisplayConfig = Omit<
OperationTypeOption,
// windows disk encryption does not have these states
"success" | "acknowledged"
>;
export const WINDOWS_DISK_ENCRYPTION_DISPLAY_CONFIG: WindowsDiskEncryptionDisplayConfig = {
verified: {
statusText: "Verified",
iconName: "success",
tooltip: () =>
"The host turned disk encryption on and sent the key to Fleet. Fleet verified.",
},
verifying: {
statusText: "Verifying",
iconName: "success-outline",
tooltip: () =>
"The host acknowledged the MDM command to turn on disk encryption. Fleet is verifying with " +
"osquery and retrieving the disk encryption key. This may take up to one hour.",
},
pending: {
statusText: "Enforcing (pending)",
iconName: "pending-outline",
tooltip: () =>
"The host will receive the MDM command to turn on disk encryption when the host comes online.",
},
action_required: {
statusText: "Action required (pending)",
iconName: "pending-outline",
tooltip: () =>
"Disk encryption is on, but the user has not set a BitLocker PIN yet.",
},
failed: {
statusText: "Failed",
iconName: "error",
tooltip: null,
},
};
type LinuxDiskEncryptionDisplayConfig = Omit<
OperationTypeOption,
"success" | "pending" | "acknowledged" | "verifying"
>;
export const LINUX_DISK_ENCRYPTION_DISPLAY_CONFIG: LinuxDiskEncryptionDisplayConfig = {
verified: {
statusText: "Verified",
iconName: "success",
tooltip: () =>
"The host turned disk encryption on and sent the key to Fleet. Fleet verified.",
},
failed: {
statusText: "Failed",
iconName: "error",
tooltip: null,
},
action_required: {
statusText: "Action required (pending)",
iconName: "pending-outline",
tooltip: TooltipInnerContentActionRequired as TooltipInnerContentFunc,
},
};