Merge contents of 7766-frontend and main, all conflicts resolved (#14429)

This commit is contained in:
Jacob Shandling 2023-10-10 15:23:55 -07:00 committed by GitHub
commit 1cb4121842
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
281 changed files with 19191 additions and 2944 deletions

View file

@ -72,7 +72,6 @@ go.mod @fleetdm/go
#
# (see website/config/custom.js for DRIs of other paths not listed here)
##############################################################################################
/website/views/pages/pricing.ejs @mikermcneil # « CEO is DRI for pricing
/handbook/company/pricing-features-table.yml @mikermcneil # « CEO is current DRI for features table
##############################################################################################

View file

@ -1,4 +1,4 @@
# Fleet 4.37.0 | Remote script execution & Puppet support.
# Fleet 4.37.0 | Puppet support.
![Fleet 4.37.0](../website/assets/images/articles/fleet-4.37.0-1600x900@2x.png)
@ -13,11 +13,12 @@ For upgrade instructions, see our [upgrade guide](https://fleetdm.com/docs/deplo
* Puppet support
* Web user interface improvements
<!--
### Introducing cross-platform script execution
_Available in Fleet Premium and Fleet Ultimate_
Fleet adds a significant new feature, allowing IT administrators and security engineers to execute shell scripts across macOS, Windows, and Linux. This addition streamlines processes, offers root-level security control, and enables swift, real-time remediation and investigation. Learn more about Fleet's [cross-platform script execution](introducing-cross-platform-script-execution).
Fleet adds a significant new feature, allowing IT administrators and security engineers to execute shell scripts across macOS, Windows, and Linux. This addition streamlines processes, offers root-level security control, and enables swift, real-time remediation and investigation. <!-- Learn more about Fleet's [cross-platform script execution](introducing-cross-platform-script-execution). -->
### Vulnerability dashboard

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

View file

@ -0,0 +1 @@
* Deprecate `mdm.macos_settings.enable_disk_encryption` in favor of `mdm.enable_disk_encryption`

View file

@ -0,0 +1,4 @@
- Added `GET /mdm/disk_encryption/summary` endpoint to get the disk encryption summary for macOS and
Windows devices.
- Added `os_settings` and `os_settings_disk_encryption` filters to `GET /hosts`, `GET /hosts/count`,
`GET /api/v1/fleet/labels/{id}/hosts` endpoints to filter hosts by OS settings.

View file

@ -0,0 +1 @@
- Added `mdm.os_settings` to `GET /api/v1/hosts/{id}` response.

View file

@ -0,0 +1 @@
* Fixed a bug that would cause live queries to stall if a detail query override was set for a team.

View file

@ -0,0 +1 @@
* Fix styling for host details/device user failing policies call out

View file

@ -0,0 +1 @@
- change Controls/Disk Encryption and host details page to include windows bitlocker information.

View file

@ -0,0 +1 @@
* Added the `POST /api/fleet/orbit/disk_encryption_key` endpoint for Windows hosts to report the bitlocker encryption key.

View file

@ -0,0 +1 @@
* Added support to return the decrypted disk encryption key of a Windows host.

View file

@ -18,6 +18,7 @@ import (
"github.com/fleetdm/fleet/v4/server/contexts/license"
"github.com/fleetdm/fleet/v4/server/datastore/mysql"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/mdm"
apple_mdm "github.com/fleetdm/fleet/v4/server/mdm/apple"
"github.com/fleetdm/fleet/v4/server/policies"
"github.com/fleetdm/fleet/v4/server/ptr"
@ -852,7 +853,7 @@ func verifyDiskEncryptionKeys(
if key.UpdatedAt.After(latest) {
latest = key.UpdatedAt
}
if _, err := apple_mdm.DecryptBase64CMS(key.Base64Encrypted, cert.Leaf, cert.PrivateKey); err != nil {
if _, err := mdm.DecryptBase64CMS(key.Base64Encrypted, cert.Leaf, cert.PrivateKey); err != nil {
undecryptable = append(undecryptable, key.HostID)
continue
}

View file

@ -1043,13 +1043,13 @@ spec:
foo: qux
name: Team1
mdm:
enable_disk_encryption: false
macos_updates:
minimum_version: 10.10.10
deadline: 1992-03-01
macos_settings:
custom_settings:
- %s
enable_disk_encryption: false
secrets:
- secret: BBB
`, mobileConfigPath))
@ -1061,9 +1061,9 @@ spec:
require.Equal(t, "[+] applied 1 teams\n", runAppForTest(t, []string{"apply", "-f", name}))
assert.JSONEq(t, string(json.RawMessage(`{"config":{"views":{"foo":"qux"}}}`)), string(*savedTeam.Config.AgentOptions))
assert.Equal(t, fleet.TeamMDM{
EnableDiskEncryption: false,
MacOSSettings: fleet.MacOSSettings{
CustomSettings: []string{mobileConfigPath},
EnableDiskEncryption: false,
CustomSettings: []string{mobileConfigPath},
},
MacOSUpdates: fleet.MacOSUpdates{
MinimumVersion: optjson.SetString("10.10.10"),
@ -1096,9 +1096,9 @@ spec:
require.True(t, ds.NewJobFuncInvoked)
// all left untouched, only setup assistant added
assert.Equal(t, fleet.TeamMDM{
EnableDiskEncryption: false,
MacOSSettings: fleet.MacOSSettings{
CustomSettings: []string{mobileConfigPath},
EnableDiskEncryption: false,
CustomSettings: []string{mobileConfigPath},
},
MacOSUpdates: fleet.MacOSUpdates{
MinimumVersion: optjson.SetString("10.10.10"),
@ -1128,9 +1128,9 @@ spec:
require.Equal(t, "[+] applied 1 teams\n", runAppForTest(t, []string{"apply", "-f", name}))
// all left untouched, only bootstrap package added
assert.Equal(t, fleet.TeamMDM{
EnableDiskEncryption: false,
MacOSSettings: fleet.MacOSSettings{
CustomSettings: []string{mobileConfigPath},
EnableDiskEncryption: false,
CustomSettings: []string{mobileConfigPath},
},
MacOSUpdates: fleet.MacOSUpdates{
MinimumVersion: optjson.SetString("10.10.10"),
@ -2885,7 +2885,7 @@ spec:
macos_settings:
enable_disk_encryption: true
`,
wantErr: `Couldn't update macos_settings because MDM features aren't turned on in Fleet.`,
wantErr: `Couldn't edit enable_disk_encryption. Neither macOS MDM nor Windows is turned on`,
},
{
desc: "app config macos_settings.enable_disk_encryption false",

View file

@ -13,6 +13,7 @@ import (
"time"
"github.com/fatih/color"
"github.com/fleetdm/fleet/v4/pkg/rawjson"
"github.com/fleetdm/fleet/v4/pkg/secure"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/service"
@ -166,12 +167,15 @@ func (eacp enrichedAppConfigPresenter) MarshalJSON() ([]byte, error) {
*fleet.VulnerabilitiesConfig
}
return json.Marshal(&struct {
fleet.EnrichedAppConfig
enrichedJSON, err := json.Marshal(fleet.EnrichedAppConfig(eacp))
if err != nil {
return nil, err
}
extraFieldsJSON, err := json.Marshal(&struct {
UpdateInterval UpdateIntervalConfigPresenter `json:"update_interval,omitempty"`
Vulnerabilities VulnerabilitiesConfigPresenter `json:"vulnerabilities,omitempty"`
}{
EnrichedAppConfig: fleet.EnrichedAppConfig(eacp),
UpdateInterval: UpdateIntervalConfigPresenter{
eacp.UpdateInterval.OSQueryDetail.String(),
eacp.UpdateInterval.OSQueryPolicy.String(),
@ -183,6 +187,13 @@ func (eacp enrichedAppConfigPresenter) MarshalJSON() ([]byte, error) {
eacp.Vulnerabilities,
},
})
if err != nil {
return nil, err
}
// we need to marshal and combine both groups separately because
// enrichedAppConfig has a custom marshaler.
return rawjson.CombineRoots(enrichedJSON, extraFieldsJSON)
}
func printConfig(c *cli.Context, config interface{}) error {

View file

@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
@ -168,15 +167,15 @@ func TestGetTeams(t *testing.T) {
}, nil
}
b, err := ioutil.ReadFile(filepath.Join("testdata", "expectedGetTeamsText.txt"))
b, err := os.ReadFile(filepath.Join("testdata", "expectedGetTeamsText.txt"))
require.NoError(t, err)
expectedText := string(b)
b, err = ioutil.ReadFile(filepath.Join("testdata", "expectedGetTeamsYaml.yml"))
b, err = os.ReadFile(filepath.Join("testdata", "expectedGetTeamsYaml.yml"))
require.NoError(t, err)
expectedYaml := string(b)
b, err = ioutil.ReadFile(filepath.Join("testdata", "expectedGetTeamsJson.json"))
b, err = os.ReadFile(filepath.Join("testdata", "expectedGetTeamsJson.json"))
require.NoError(t, err)
// must read each JSON value separately and compact it
var buf bytes.Buffer
@ -206,8 +205,8 @@ func TestGetTeams(t *testing.T) {
errBuffer.Reset()
actualJSON, err := runWithErrWriter([]string{"get", "teams", "--json"}, &errBuffer)
require.NoError(t, err)
require.Equal(t, expectedJson, actualJSON.String())
require.Equal(t, errBuffer.String() == expiredBanner.String(), tt.shouldHaveExpiredBanner)
require.Equal(t, expectedJson, actualJSON.String())
errBuffer.Reset()
actualYaml, err := runWithErrWriter([]string{"get", "teams", "--yaml"}, &errBuffer)
@ -433,7 +432,7 @@ func TestGetHosts(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
expected, err := ioutil.ReadFile(filepath.Join("testdata", tt.goldenFile))
expected, err := os.ReadFile(filepath.Join("testdata", tt.goldenFile))
require.NoError(t, err)
expectedResults := tt.scanner(string(expected))
actualResult := tt.scanner(runAppForTest(t, tt.args))
@ -536,7 +535,7 @@ func TestGetHostsMDM(t *testing.T) {
}
if tt.goldenFile != "" {
expected, err := ioutil.ReadFile(filepath.Join("testdata", tt.goldenFile))
expected, err := os.ReadFile(filepath.Join("testdata", tt.goldenFile))
require.NoError(t, err)
if ext := filepath.Ext(tt.goldenFile); ext == ".json" {
// the output of --json is not a json array, but a list of

View file

@ -86,6 +86,7 @@
"enabled_and_configured": false,
"apple_bm_default_team": "",
"windows_enabled_and_configured": false,
"enable_disk_encryption": false,
"macos_updates": {
"minimum_version": null,
"deadline": null
@ -96,8 +97,7 @@
"webhook_url": ""
},
"macos_settings": {
"custom_settings": null,
"enable_disk_encryption": false
"custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,

View file

@ -19,6 +19,7 @@ spec:
enabled_and_configured: false
apple_bm_default_team: ""
windows_enabled_and_configured: false
enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
@ -28,7 +29,6 @@ spec:
deadline: null
macos_settings:
custom_settings:
enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false

View file

@ -44,6 +44,7 @@
"apple_bm_enabled_and_configured": false,
"enabled_and_configured": false,
"windows_enabled_and_configured": false,
"enable_disk_encryption": false,
"macos_updates": {
"minimum_version": null,
"deadline": null
@ -54,8 +55,7 @@
"webhook_url": ""
},
"macos_settings": {
"custom_settings": null,
"enable_disk_encryption": false
"custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,

View file

@ -19,6 +19,7 @@ spec:
apple_bm_terms_expired: false
enabled_and_configured: false
windows_enabled_and_configured: false
enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
@ -28,7 +29,6 @@ spec:
deadline: null
macos_settings:
custom_settings:
enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false

View file

@ -24,13 +24,13 @@
"enable_software_inventory": true
},
"mdm": {
"enable_disk_encryption": false,
"macos_updates": {
"minimum_version": null,
"deadline": null
},
"macos_settings": {
"custom_settings": null,
"enable_disk_encryption": false
"custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,
@ -84,13 +84,13 @@
}
},
"mdm": {
"enable_disk_encryption": false,
"macos_updates": {
"minimum_version": "12.3.1",
"deadline": "2021-12-14"
},
"macos_settings": {
"custom_settings": null,
"enable_disk_encryption": false
"custom_settings": null
},
"macos_setup": {
"bootstrap_package": null,

View file

@ -7,12 +7,12 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
enable_disk_encryption: false
macos_updates:
minimum_version: null
deadline: null
macos_settings:
custom_settings:
enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false
@ -36,12 +36,12 @@ spec:
enable_host_users: false
enable_software_inventory: false
mdm:
enable_disk_encryption: false
macos_updates:
minimum_version: "12.3.1"
deadline: "2021-12-14"
macos_settings:
custom_settings:
enable_disk_encryption: false
macos_setup:
bootstrap_package:
enable_end_user_authentication: false

View file

@ -19,13 +19,13 @@ spec:
apple_bm_terms_expired: false
enabled_and_configured: true
windows_enabled_and_configured: false
enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
webhook_url: ""
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: null
enable_end_user_authentication: false

View file

@ -19,13 +19,13 @@ spec:
apple_bm_terms_expired: false
enabled_and_configured: true
windows_enabled_and_configured: false
enable_disk_encryption: false
macos_migration:
enable: false
mode: ""
webhook_url: ""
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: %s
enable_end_user_authentication: false

View file

@ -7,9 +7,9 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
enable_disk_encryption: false
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: null
enable_end_user_authentication: false
@ -27,9 +27,9 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
enable_disk_encryption: false
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: null
macos_setup_assistant: null

View file

@ -7,9 +7,9 @@ spec:
enable_host_users: true
enable_software_inventory: true
mdm:
enable_disk_encryption: false
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: %s
enable_end_user_authentication: false
@ -27,9 +27,9 @@ spec:
enable_host_users: false
enable_software_inventory: false
mdm:
enable_disk_encryption: false
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: %s
macos_setup_assistant: %s

View file

@ -7,9 +7,9 @@ spec:
enable_host_users: false
enable_software_inventory: false
mdm:
enable_disk_encryption: false
macos_settings:
custom_settings: null
enable_disk_encryption: false
macos_setup:
bootstrap_package: null
enable_end_user_authentication: false

View file

@ -529,8 +529,10 @@ Use with caution as this may break Fleet ingestion of hosts data.
```yaml
features:
detail_query_overrides:
# null allows to disable the "users" query from running on hosts.
# null disables the "users" query from running on hosts.
users: null
# "" disables the "disk_encryption_linux" query from running on hosts.
disk_encryption_linux: ""
# this replaces the hardcoded "mdm" detail query.
mdm: "SELECT enrolled, server_url, installed_from_dep, payload_identifier FROM mdm;"
```

View file

@ -533,6 +533,7 @@ The MDM endpoints exist to support the related command-line interface sub-comman
- [Complete SSO during DEP enrollment](#complete-sso-during-dep-enrollment)
- [Preassign profiles to devices](#preassign-profiles-to-devices)
- [Match preassigned profiles](#match-preassigned-profiles)
- [Get FileVault statistics](#get-filevault-statistics)
### Generate Apple DEP Key Pair
@ -701,6 +702,44 @@ This endpoint stores a profile to be assigned to a host at some point in the fut
`Status: 204`
### Get FileVault statistics
_Available in Fleet Premium_
Get aggregate status counts of disk encryption enforced on macOS hosts.
The summary can optionally be filtered by team id.
`GET /api/v1/fleet/mdm/apple/filevault/summary`
#### Parameters
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | string | query | _Available in Fleet Premium_ The team id to filter the summary. |
#### Example
Get aggregate status counts of Apple disk encryption profiles applying to macOS hosts enrolled to Fleet's MDM that are not assigned to any team.
`GET /api/v1/fleet/mdm/apple/filevault/summary`
##### Default response
`Status: 200`
```json
{
"verified": 123,
"verifying": 123,
"action_required": 123,
"enforcing": 123,
"failed": 123,
"removing_enforcement": 123
}
```
### Match preassigned profiles
_Available in Fleet Premium_
@ -2291,7 +2330,9 @@ Gets all information required by Fleet Desktop, this includes things like the nu
{
"failing_policies_count": 3,
"notifications": {
"needs_mdm_migration": true
"needs_mdm_migration": true,
"renew_enrollment_profile": false,
"enforce_bitlocker_encryption": false,
},
"config": {
"org_info": {
@ -2313,6 +2354,7 @@ In regards to the `notifications` key:
- `needs_mdm_migration` means that the device fits all the requirements to allow the user to initiate an MDM migration to Fleet.
- `renew_enrollment_profile` means that the device is currently unmanaged from MDM but should be DEP enrolled into Fleet.
- `enforce_bitlocker_encryption` applies only to Windows devices and means that it should encrypt the disk and report the encryption key back to Fleet.
#### Get device's policies

View file

@ -93,6 +93,7 @@ If you also have Fleetd running on hosts, it will need access to these API endpo
* `/api/fleet/orbit/ping`
* `/api/fleet/orbit/scripts/request`
* `/api/fleet/orbit/scripts/result`
* `/api/fleet/orbit/disk_encryption_key`
* `/api/osquery/log`
<meta name="description" value="Find commonly asked questions and answers about contributing to Fleet as part of our community.">

View file

@ -12,7 +12,7 @@ Fleetctl (pronouced “fleet control”) is a CLI (command line interface) tool
## Fleetd
Fleetd is a bundle of agents provided by Fleet to gather information about your devices. Fleetd includes [osquery](https://www.osquery.io/), Orbit, and Fleet Desktop. [Docs](https://fleetdm.com/docs/using-fleet/fleet-ui).
Fleetd is a bundle of agents provided by Fleet to gather information about your devices. Fleetd includes [osquery](https://www.osquery.io/), Orbit, and Fleet Desktop. [Docs](https://fleetdm.com/docs/using-fleet/fleetd).
## Osquery
Osquery is an open-source tool for gathering information about the state of any device that the osquery agent has been installed on. [Learn more](https://www.osquery.io/).

View file

@ -1829,14 +1829,14 @@ the `software` table.
| page | integer | query | Page number of the results to fetch. |
| per_page | integer | query | Results per page. |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. **Note:** Use `page` instead of `after`. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an `@`, no space, etc.). |
| additional_info_filters | string | query | A comma-delimited list of fields to include in each host's additional information object. See [Fleet Configuration Options](https://fleetdm.com/docs/using-fleet/fleetctl-cli#fleet-configuration-options) for an example configuration with hosts' additional information. Use `*` to get all stored fields. |
| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. **Note:** Use `page` instead of `after` |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an '@', no space, etc.). |
| additional_info_filters | string | query | A comma-delimited list of fields to include in each host's additional information object. See [Fleet Configuration Options](https://fleetdm.com/docs/using-fleet/fleetctl-cli#fleet-configuration-options) for an example configuration with hosts' additional information. Use '*' to get all stored fields. |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| policy_id | integer | query | The ID of the policy to filter hosts by. |
| policy_response | string | query | Valid options are `passing` or `failing`. `policy_id` must also be specified with `policy_response`. |
| policy_response | string | query | Valid options are 'passing' or 'failing'. `policy_id` must also be specified with `policy_response`. |
| software_id | integer | query | The ID of the software to filter hosts by. |
| os_id | integer | query | The ID of the operating system to filter hosts by. |
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
@ -1845,7 +1845,7 @@ the `software` table.
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team ID filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| disable_failing_policies| boolean | query | If "true", hosts will return failing policies as 0 regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
@ -1858,9 +1858,9 @@ If `software_id` is specified, an additional top-level key `"software"` is retur
If `mdm_id` is specified, an additional top-level key `"mobile_device_management_solution"` is returned with the information corresponding to the `mdm_id`.
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
If `mdm_id`, `mdm_name`, `mdm_enrollment_status`, `os_settings`, or `os_settings_disk_encryption` is specified, then Windows Servers are excluded from the results.
If `munki_issue_id` is specified, an additional top-level key `"munki_issue"` is returned with the information corresponding to the `munki_issue_id`.
If `munki_issue_id` is specified, an additional top-level key `munki_issue` is returned with the information corresponding to the `munki_issue_id`.
If `after` is being used with `created_at` or `updated_at`, the table must be specified in `order_key`. Those columns become `h.created_at` and `h.updated_at`.
@ -1988,13 +1988,13 @@ Response payload with the `munki_issue_id` filter provided:
| Name | Type | In | Description |
| ----------------------- | ------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. |
| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an `@`, no space, etc.). |
| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an '@', no space, etc.). |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| policy_id | integer | query | The ID of the policy to filter hosts by. |
| policy_response | string | query | Valid options are `passing` or `failing`. `policy_id` must also be specified with `policy_response`. |
| policy_response | string | query | Valid options are 'passing' or 'failing'. `policy_id` must also be specified with `policy_response`. |
| software_id | integer | query | The ID of the software to filter hosts by. |
| os_id | integer | query | The ID of the operating system to filter hosts by. |
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
@ -2003,7 +2003,7 @@ Response payload with the `munki_issue_id` filter provided:
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team ID filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of `verified`, `verifying`, `action_required`, `enforcing`, `failed`, or `removing_enforcement`. |
@ -2555,6 +2555,9 @@ Returns the information of the host specified using the `uuid`, `osquery_host_id
"bootstrap_package_status": "installed",
"detail": ""
},
"os_settings": {
"disk_encryption": null
},
"profiles": [
{
"profile_id": 999,
@ -2743,6 +2746,9 @@ This is the API route used by the **My device** page in Fleet desktop to display
"detail": "",
"bootstrap_package_name": "test.pkg"
},
"os_settings": {
"disk_encryption": null
},
"profiles": [
{
"profile_id": 999,
@ -3291,12 +3297,12 @@ requested by a web browser.
| format | string | query | **Required**, must be "csv" (only supported format for now). |
| columns | string | query | Comma-delimited list of columns to include in the report (returns all columns if none is specified). |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, `ipv4` and the hosts' email addresses (only searched if the query looks like an email address, i.e. contains an `@`, no space, etc.). |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| policy_id | integer | query | The ID of the policy to filter hosts by. |
| policy_response | string | query | Valid options are `passing` or `failing`. `policy_id` must also be specified with `policy_response`. **Note: If `policy_id` is specified _without_ including `policy_response`, this will also return hosts where the policy is not configured to run or failed to run.** |
| policy_response | string | query | Valid options are 'passing' or 'failing'. `policy_id` must also be specified with `policy_response`. **Note: If `policy_id` is specified _without_ including `policy_response`, this will also return hosts where the policy is not configured to run or failed to run.** |
| software_id | integer | query | The ID of the software to filter hosts by. |
| os_id | integer | query | The ID of the operating system to filter hosts by. |
| os_name | string | query | The name of the operating system to filter hosts by. `os_version` must also be specified with `os_name` |
@ -3304,7 +3310,7 @@ requested by a web browser.
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team ID filter, the results include only hosts that are not assigned to any team.** |
| munki_issue_id | integer | query | The ID of the _munki issue_ (a Munki-reported error or warning message) to filter hosts by (that is, filter hosts that are affected by that corresponding error or warning message). |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| label_id | integer | query | A valid label ID. Can only be used in combination with `order_key`, `order_direction`, `status`, `query` and `team_id`. |
@ -3330,7 +3336,7 @@ created_at,updated_at,id,detail_updated_at,label_updated_at,policy_updated_at,la
### Get host's disk encryption key
Requires the [macadmins osquery extension](https://github.com/macadmins/osquery-extension) which comes bundled
For macOS, requires the [macadmins osquery extension](https://github.com/macadmins/osquery-extension) which comes bundled
in [Fleet's osquery installers](https://fleetdm.com/docs/using-fleet/adding-hosts#osquery-installer).
Requires Fleet's MDM properly [enabled and configured](https://fleetdm.com/docs/using-fleet/mdm-macos-setup).
@ -3724,21 +3730,21 @@ Returns a list of the hosts that belong to the specified label.
| page | integer | query | Page number of the results to fetch. |
| per_page | integer | query | Results per page. |
| order_key | string | query | What to order results by. Can be any column in the hosts table. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include `asc` and `desc`. Default is `asc`. |
| order_direction | string | query | **Requires `order_key`**. The direction of the order given the order key. Options include 'asc' and 'desc'. Default is 'asc'. |
| after | string | query | The value to get results after. This needs `order_key` defined, as that's the column that would be used. |
| status | string | query | Indicates the status of the hosts to return. Can either be `new`, `online`, `offline`, `mia` or `missing`. |
| status | string | query | Indicates the status of the hosts to return. Can either be 'new', 'online', 'offline', 'mia' or 'missing'. |
| query | string | query | Search query keywords. Searchable fields include `hostname`, `machine_serial`, `uuid`, and `ipv4`. |
| team_id | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts in the specified team. |
| disable_failing_policies | boolean | query | If "true", hosts will return failing policies as 0 regardless of whether there are any that failed for the host. This is meant to be used when increased performance is needed in exchange for the extra information. |
| mdm_id | integer | query | The ID of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider and URL). |
| mdm_name | string | query | The name of the _mobile device management_ (MDM) solution to filter hosts by (that is, filter hosts that use a specific MDM provider). |
| mdm_enrollment_status | string | query | The _mobile device management_ (MDM) enrollment status to filter hosts by. Can be one of 'manual', 'automatic', 'enrolled', 'pending', or 'unenrolled'. |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
| macos_settings | string | query | Filters the hosts by the status of the _mobile device management_ (MDM) profiles applied to hosts. Can be one of 'verified', 'verifying', 'pending', or 'failed'. **Note: If this filter is used in Fleet Premium without a team ID filter, the results include only hosts that are not assigned to any team.** |
| low_disk_space | integer | query | _Available in Fleet Premium_ Filters the hosts to only include hosts with less GB of disk space available than this value. Must be a number between 1-100. |
| macos_settings_disk_encryption | string | query | Filters the hosts by the status of the macOS disk encryption MDM profile on the host. Can be one of `verified`, `verifying`, `action_required`, `enforcing`, `failed`, or `removing_enforcement`. |
| bootstrap_package | string | query | _Available in Fleet Premium_ Filters the hosts by the status of the MDM bootstrap package on the host. Can be one of `installed`, `pending`, or `failed`. **Note: If this filter is used in Fleet Premium without a team id filter, the results include only hosts that are not assigned to any team.** |
If `mdm_id`, `mdm_name` or `mdm_enrollment_status` is specified, then Windows Servers are excluded from the results.
If `mdm_id`, `mdm_name`, `mdm_enrollment_status`, `os_settings`, or `os_settings_disk_encryption` is specified, then Windows Servers are excluded from the results.
#### Example
@ -3887,8 +3893,8 @@ Add a configuration profile to enforce custom settings on macOS hosts.
| Name | Type | In | Description |
| ------------------------- | -------- | ---- | ------------------------------------------------------------------------- |
| profile | file | form | **Required**. The mobileconfig file containing the profile. |
| team_id | string | form | _Available in Fleet Premium_ The team id for the profile. If specified, the profile is applied to only hosts that are assigned to the specified team. If not specified, the profile is applied to only to hosts that are not assigned to any team. |
| profile | file | form | **Required**. The .mobileconfig file containing the profile. |
| team_id | string | form | _Available in Fleet Premium_ The team ID for the profile. If specified, the profile is applied to only hosts that are assigned to the specified team. If not specified, the profile is applied to only to hosts that are not assigned to any team. |
#### Example
@ -3967,7 +3973,7 @@ results (i.e., only profiles that are associated with "No team" are listed).
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | string | query | _Available in Fleet Premium_ The team id to filter profiles. |
| team_id | string | query | _Available in Fleet Premium_ The team ID to filter profiles. |
#### Example
@ -4090,11 +4096,11 @@ _Available in Fleet Premium_
_Available in Fleet Premium_
Get aggregate status counts of disk encryption enforced on hosts.
Get aggregate status counts of disk encryption enforced on macOS and Windows hosts.
The summary can optionally be filtered by team id.
The summary can optionally be filtered by team ID.
`GET /api/v1/fleet/mdm/apple/filevault/summary`
`GET /api/v1/fleet/mdm/disk_encryption/summary`
#### Parameters
@ -4104,9 +4110,9 @@ The summary can optionally be filtered by team id.
#### Example
Get aggregate status counts of Apple disk encryption profiles applying to macOS hosts enrolled to Fleet's MDM that are not assigned to any team.
Get aggregate disk encryption status counts of macOS and Windows hosts enrolled to Fleet's MDM that are not assigned to any team.
`GET /api/v1/fleet/mdm/apple/filevault/summary`
`GET /api/v1/fleet/mdm/disk_encryption/summary`
##### Default response
@ -4114,12 +4120,12 @@ Get aggregate status counts of Apple disk encryption profiles applying to macOS
```json
{
"verified": 123,
"verifying": 123,
"action_required": 123,
"enforcing": 123,
"failed": 123,
"removing_enforcement": 123
"verified": {"macos": 123, "windows": 123},
"verifying": {"macos": 123, "windows": 0},
"action_required": {"macos": 123, "windows": 0},
"enforcing": {"macos": 123, "windows": 123},
"failed": {"macos": 123, "windows": 123},
"removing_enforcement": {"macos": 123, "windows": 0},
}
```
@ -4128,7 +4134,7 @@ Get aggregate status counts of Apple disk encryption profiles applying to macOS
Get aggregate status counts of all macOS settings (configuraiton profiles and disk encryption) enforced on hosts.
For Fleet Premium uses, the statistics can
optionally be filtered by team id. If no team id is specified, team profiles are excluded from the
optionally be filtered by team ID. If no team ID is specified, team profiles are excluded from the
results (i.e., only profiles that are associated with "No team" are listed).
`GET /api/v1/fleet/mdm/apple/profiles/summary`
@ -4137,7 +4143,7 @@ results (i.e., only profiles that are associated with "No team" are listed).
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | string | query | _Available in Fleet Premium_ The team id to filter profiles. |
| team_id | string | query | _Available in Fleet Premium_ The team ID to filter profiles. |
#### Example
@ -4274,7 +4280,7 @@ Sets the custom MDM setup enrollment profile for a team or no team.
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | integer | json | The team id this custom enrollment profile applies to, or no team if omitted. |
| team_id | integer | json | The team ID this custom enrollment profile applies to, or no team if omitted. |
| name | string | json | The filename of the uploaded custom enrollment profile. |
| enrollment_profile | object | json | The custom enrollment profile's json, as documented in https://developer.apple.com/documentation/devicemanagement/profile. |
@ -4310,7 +4316,7 @@ Gets the custom MDM setup enrollment profile for a team or no team.
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | integer | query | The team id for which to return the custom enrollment profile, or no team if omitted. |
| team_id | integer | query | The team ID for which to return the custom enrollment profile, or no team if omitted. |
#### Example
@ -4344,7 +4350,7 @@ Deletes the custom MDM setup enrollment profile assigned to a team or no team.
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | integer | query | The team id for which to delete the custom enrollment profile, or no team if omitted. |
| team_id | integer | query | The team ID for which to delete the custom enrollment profile, or no team if omitted. |
#### Example
@ -4439,7 +4445,7 @@ Upload a bootstrap package that will be automatically installed during DEP setup
| Name | Type | In | Description |
| ------- | ------ | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| package | file | form | **Required**. The bootstrap package installer. It must be a signed `pkg` file. |
| team_id | string | form | The team id for the package. If specified, the package will be installed to hosts that are assigned to the specified team. If not specified, the package will be installed to hosts that are not assigned to any team. |
| team_id | string | form | The team ID for the package. If specified, the package will be installed to hosts that are assigned to the specified team. If not specified, the package will be installed to hosts that are not assigned to any team. |
#### Example
@ -4485,7 +4491,7 @@ Get information about a bootstrap package that was uploaded to Fleet.
| Name | Type | In | Description |
| ------- | ------ | --- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| team_id | string | url | **Required** The team id for the package. Zero (0) can be specified to get information about the bootstrap package for hosts that don't belong to a team. |
| team_id | string | url | **Required** The team ID for the package. Zero (0) can be specified to get information about the bootstrap package for hosts that don't belong to a team. |
| for_update | boolean | query | If set to `true`, the authorization will be for a `write` action instead of a `read`. Useful for the write-only `gitops` role when requesting the bootstrap metadata to check if the package needs to be replaced. |
#### Example
@ -4523,7 +4529,7 @@ Delete a team's bootstrap package.
| Name | Type | In | Description |
| ------- | ------ | --- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| team_id | string | url | **Required** The team id for the package. Zero (0) can be specified to get information about the bootstrap package for hosts that don't belong to a team. |
| team_id | string | url | **Required** The team ID for the package. Zero (0) can be specified to get information about the bootstrap package for hosts that don't belong to a team. |
#### Example
@ -4570,7 +4576,7 @@ _Available in Fleet Premium_
Get aggregate status counts of bootstrap packages delivered to DEP enrolled hosts.
The summary can optionally be filtered by team id.
The summary can optionally be filtered by team ID.
`GET /api/v1/fleet/mdm/apple/bootstrap/summary`
@ -4578,7 +4584,7 @@ The summary can optionally be filtered by team id.
| Name | Type | In | Description |
| ------------------------- | ------ | ----- | ------------------------------------------------------------------------- |
| team_id | string | query | The team id to filter the summary. |
| team_id | string | query | The team ID to filter the summary. |
#### Example
@ -5157,7 +5163,7 @@ Team policies work the same as policies, but at the team level.
| Name | Type | In | Description |
| ------------------ | ------- | ---- | ------------------------------------------------------------------------------------------------------------- |
| id | integer | url | Required. Defines what team id to operate on |
| id | integer | url | Required. Defines what team ID to operate on |
| page | integer | query | Page number of the results to fetch. |
| per_page | integer | query | Results per page. |
#### Example
@ -5261,7 +5267,7 @@ Team policies work the same as policies, but at the team level.
| Name | Type | In | Description |
| ------------------ | ------- | ---- | ------------------------------------------------------------------------------------------------------------- |
| team_id | integer | url | Defines what team id to operate on |
| team_id | integer | url | Defines what team ID to operate on |
| id | integer | path | **Required.** The policy's ID. |
#### Example
@ -5304,7 +5310,7 @@ The semantics for creating a team policy are the same as for global policies, se
| Name | Type | In | Description |
| ---------- | ------- | ---- | ------------------------------------ |
| team_id | integer | url | Defines what team id to operate on. |
| team_id | integer | url | Defines what team ID to operate on. |
| name | string | body | The query's name. |
| query | string | body | The query in SQL. |
| description | string | body | The query's description. |
@ -5366,7 +5372,7 @@ Either `query` or `query_id` must be provided.
| Name | Type | In | Description |
| -------- | ------- | ---- | ------------------------------------------------- |
| team_id | integer | url | Defines what team id to operate on |
| team_id | integer | url | Defines what team ID to operate on |
| ids | list | body | **Required.** The IDs of the policies to delete. |
#### Example
@ -6600,7 +6606,8 @@ Deletes the session specified by ID. When the user associated with the session n
"epss_probability": 0.01537,
"cisa_known_exploit": false,
"cve_published": "2022-01-01 12:32:00",
"cve_description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match."
"cve_description": "In the GNU C Library (aka glibc or libc6) before 2.28, parse_reg_exp in posix/regcomp.c misparses alternatives, which allows attackers to cause a denial of service (assertion failure and application exit) or trigger an incorrect result by attempting a regular-expression match.",
"resolved_in_version": "2.28"
}
],
"hosts_count": 1

View file

@ -170,127 +170,11 @@ The following CIS benchmark checks cannot be automated and must be addressed man
Fleet's policies have been written against v1.12.0 of the benchmark. You can refer to the [CIS website](https://www.cisecurity.org/cis-benchmarks) for full details about this version.
### Checks that require a Group Policy Template
### Checks that require a Group Policy template
38 items require Group Policy Template in place in order to audit them.
Several items require Group Policy templates in place in order to audit them.
These items are tagged with the label `CIS_group_policy_template_required` in the YAML file, and details about the required Group Policy templates can be found in each item's `resolution`.
```
18.3.1 CIS - Ensure 'Apply UAC restrictions to local accounts on network logons' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Apply UAC restrictions to local accounts on network logons'
18.3.2 CIS - Ensure 'Configure SMB v1 client driver' is set to 'Enabled: Disable driver (recommended)'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Configure SMB v1 client driver'
18.3.3 CIS - Ensure 'Configure SMB v1 server' is set to 'Disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Configure SMB v1 server'
18.3.4 CIS - Ensure 'Enable Structured Exception Handling Overwrite Protection (SEHOP)' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Enable Structured Exception Handling Overwrite Protection (SEHOP)'
18.3.5 CIS - Ensure 'Limits print driver installation to Administrators' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\Limits print driver installation to Administrators'
18.3.6 CIS - Ensure 'NetBT NodeType configuration' is set to 'Enabled: P-node (recommended)'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\NetBT NodeType configuration'
18.3.7 CIS - Ensure 'WDigest Authentication' is set to 'Disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MS Security Guide\WDigest Authentication (disabling may require KB2871997)'
18.4.1 CIS - Ensure 'MSS: (AutoAdminLogon) Enable Automatic Logon (not recommended)' is set to 'Disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (AutoAdminLogon) Enable Automatic Logon (not recommended)'
18.4.2 CIS - Ensure 'MSS: (DisableIPSourceRouting IPv6) IP source routing protection level (protects against packet spoofing)' is set to 'Enabled: Highest protection, source routing is completely disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (DisableIPSourceRouting IPv6) IP source routing protection level (protects against packet spoofing)'
18.4.3 CIS - Ensure 'MSS: (DisableIPSourceRouting) IP source routing protection level (protects against packet spoofing)' is set to 'Enabled: Highest protection, source routing is completely disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (DisableIPSourceRouting) IP source routing protection level (protects against packet spoofing)'
18.4.4 CIS - Ensure 'MSS: (DisableSavePassword) Prevent the dial-up password from being saved' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS:(DisableSavePassword) Prevent the dial-up password from being saved'
18.4.5 CIS - Ensure 'MSS: (EnableICMPRedirect) Allow ICMP redirects to override OSPF generated routes' is set to 'Disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (EnableICMPRedirect) Allow ICMP redirects to override OSPF generated routes'
18.4.6 CIS - Ensure 'MSS: (KeepAliveTime) How often keep-alive packets are sent in milliseconds' is set to 'Enabled: 300,000 or 5 minutes'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (KeepAliveTime) How often keep-alive packets are sent in milliseconds'
18.4.7 CIS - Ensure 'MSS: (NoNameReleaseOnDemand) Allow the computer to ignore NetBIOS name release requests except from WINS servers' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (NoNameReleaseOnDemand) Allow the computer to ignore NetBIOS name release requests except from WINS servers'
18.4.8 CIS - Ensure 'MSS: (PerformRouterDiscovery) Allow IRDP to detect and configure Default Gateway addresses (could lead to DoS)' is set to 'Disabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (PerformRouterDiscovery) Allow IRDP to detect and configure Default Gateway addresses (could lead to DoS)'
18.4.9 CIS - Ensure 'MSS: (SafeDllSearchMode) Enable Safe DLL search mode (recommended)' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (SafeDllSearchMode) Enable Safe DLL search mode (recommended)'
18.4.10 CIS - Ensure 'MSS: (ScreenSaverGracePeriod) The time in seconds before the screen saver grace period expires (0 recommended)' is set to 'Enabled: 5 or fewer seconds'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (ScreenSaverGracePeriod) The time in seconds before the screen saver grace period expires (0 recommended)'
18.4.11 CIS - Ensure 'MSS: (TcpMaxDataRetransmissions IPv6) How many times unacknowledged data is retransmitted' is set to 'Enabled: 3'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS:(TcpMaxDataRetransmissions IPv6) How many times unacknowledged data is retransmitted'
18.4.12 CIS - Ensure 'MSS: (TcpMaxDataRetransmissions) How many times unacknowledged data is retransmitted' is set to 'Enabled: 3'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS:(TcpMaxDataRetransmissions) How many times unacknowledged data is retransmitted'
18.4.13 CIS - Ensure 'MSS: (WarningLevel) Percentage threshold for the security event log at which the system will generate a warning' is set to 'Enabled: 90% or less'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\MSS (Legacy)\MSS: (WarningLevel) Percentage threshold for the security event log at which the system will generate a warning'
18.8.21.2 CIS - Ensure 'Configure registry policy processing: Do not apply during periodic background processing' is set to 'Enabled: FALSE'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Group Policy\Configure registry policy processing'
18.8.22.1.1 CIS - Ensure 'Turn off access to the Store' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off access to the Store'
18.8.22.1.2 CIS - Ensure 'Turn off downloading of print drivers over HTTP' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off downloading of print drivers over HTTP'
18.8.22.1.3 CIS - Ensure 'Turn off handwriting personalization data sharing' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off handwriting personalization data sharing'
18.8.22.1.4 CIS - Ensure 'Turn off handwriting recognition error reporting' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off handwriting recognition error reporting'
18.8.22.1.5 CIS - Ensure 'Turn off Internet Connection Wizard if URL connection is referring to Microsoft.com' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Internet Connection Wizard if URL connection is referring to Microsoft.com'
18.8.22.1.6 CIS - Ensure 'Turn off Internet download for Web publishing and online ordering wizards' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Internet download for Web publishing and online ordering wizards'
18.8.22.1.7 CIS - Ensure 'Turn off printing over HTTP' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off printing over HTTP'
18.8.22.1.8 CIS - Ensure 'Turn off Registration if URL connection is referring to Microsoft.com' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Registration if URL connection is referring to Microsoft.com'
18.8.22.1.9 CIS - Ensure 'Turn off Search Companion content file updates' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Search Companion content file updates'
18.8.22.1.10 CIS - Ensure 'Turn off the "Order Prints" picture task' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off the "Order Prints" picture task'
18.8.22.1.11 CIS - Ensure 'Turn off the "Publish to Web" task for files and folders' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off the "Publish to Web" task for files and folders'
18.8.22.1.12 CIS - Ensure 'Turn off the Windows Messenger Customer Experience Improvement Program' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off the Windows Messenger Customer Experience Improvement Program'
18.8.22.1.13 CIS - Ensure 'Turn off Windows Customer Experience Improvement Program' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Windows Customer Experience Improvement Program'
18.8.22.1.14 CIS - Ensure 'Turn off Windows Error Reporting' is set to 'Enabled'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Internet Communication Management\Internet Communication settings\Turn off Windows Error Reporting'
18.8.25.1 CIS - Ensure 'Support device authentication using certificate' is set to 'Enabled: Automatic'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Kerberos\Support device authentication using certificate'
18.8.26.1 CIS - Ensure 'Enumeration policy for external devices incompatible with Kernel DMA Protection' is set to 'Enabled: Block All'
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Kernel DMA Protection\Enumeration policy for external devices incompatible with Kernel DMA Protection'
18.8.27.1 CIS - Ensure 'Disallow copying of user input methods to the system account for sign-in' is set to 'Enabled' (Automated)
Requires this GPO in place: 'Computer Configuration\Policies\Administrative Templates\System\Locale Services\Disallow copying of user input methods to the system account for sign-in'
```
## Performance testing
In August 2023, we completed scale testing on 10k Windows hosts and 70k macOS hosts. Ultimately, we validated both server and host performance at that scale.

View file

@ -52,7 +52,7 @@ Fleet allows you to schedule queries to run at a set frequency. Scheduled querie
The default log destination, **filesystem**, is good to start. With this set, data is sent to the `/var/log/osquery/osqueryd.snapshots.log` file on each hosts filesystem. To see which log destinations are available in Fleet, head to the [log destinations page](https://fleetdm.com/docs/using-fleet/log-destinations).
By default, queries that run on a schedule will only target platforms compatible with that query. This behavior can be overridden by setting the platforms in the "advanced options" when saving a query.
By default, queries that run on a schedule will only target platforms compatible with that query. This behavior can be overridden by setting the platforms in "advanced options" when saving a query.
**How to schedule queries:**
@ -94,4 +94,4 @@ See "[Agent configuration](https://fleetdm.com/docs/configuration/agent-configur
<meta name="title" value="Fleet UI">
<meta name="pageOrderInSection" value="200">
<meta name="description" value="Learn how to create, run, and schedule queries, as well as update agent options in the Fleet user interface.">
<meta name="navSection" value="The basics">
<meta name="navSection" value="The basics">

View file

@ -75,7 +75,7 @@ GitOps is an API-only and write-only role that can be used on CI/CD pipelines.
| View Apple mobile device management (MDM) certificate information | | | | ✅ | |
| View Apple business manager (BM) information | | | | ✅ | |
| Generate Apple mobile device management (MDM) certificate signing request (CSR) | | | | ✅ | |
| View disk encryption key for macOS hosts | ✅ | ✅ | ✅ | ✅ | |
| View disk encryption key for macOS and Windows hosts | ✅ | ✅ | ✅ | ✅ | |
| Create edit and delete configuration profiles for macOS hosts | | | ✅ | ✅ | ✅ |
| Execute MDM commands on macOS and Windows hosts*** | | | ✅ | ✅ | |
| View results of MDM commands executed on macOS and Windows hosts*** | ✅ | ✅ | ✅ | ✅ | |

View file

@ -15,6 +15,7 @@ import (
"strings"
"github.com/fleetdm/fleet/v4/pkg/file"
"github.com/fleetdm/fleet/v4/pkg/optjson"
"github.com/fleetdm/fleet/v4/server/authz"
"github.com/fleetdm/fleet/v4/server/contexts/ctxdb"
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
@ -890,12 +891,7 @@ func (svc *Service) getOrCreatePreassignTeam(ctx context.Context, groups []strin
}
payload.MDM = &fleet.TeamPayloadMDM{
MacOSSettings: &fleet.MacOSSettings{
// teams created by the match endpoint have disk encryption
// enabled by default.
// TODO: maybe make this configurable?
EnableDiskEncryption: true,
},
EnableDiskEncryption: optjson.SetBool(true),
MacOSSetup: &fleet.MacOSSetup{
MacOSSetupAssistant: ac.MDM.MacOSSetup.MacOSSetupAssistant,
// NOTE: BootstrapPackage is currently ignored by svc.ModifyTeam and gets set
@ -968,3 +964,51 @@ func teamNameFromPreassignGroups(groups []string) string {
return strings.Join(groups, " - ")
}
func (svc *Service) GetMDMDiskEncryptionSummary(ctx context.Context, teamID *uint) (*fleet.MDMDiskEncryptionSummary, error) {
// TODO: Consider adding a new generic OSSetting type or Windows-specific type for authz checks
// like this.
if err := svc.authz.Authorize(ctx, fleet.MDMAppleConfigProfile{TeamID: teamID}, fleet.ActionRead); err != nil {
return nil, ctxerr.Wrap(ctx, err)
}
var macOS fleet.MDMAppleFileVaultSummary
if m, err := svc.ds.GetMDMAppleFileVaultSummary(ctx, teamID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "getting filevault summary")
} else if m != nil {
macOS = *m
}
var windows fleet.MDMWindowsBitLockerSummary
if w, err := svc.ds.GetMDMWindowsBitLockerSummary(ctx, teamID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "getting bitlocker summary")
} else if w != nil {
windows = *w
}
return &fleet.MDMDiskEncryptionSummary{
Verified: fleet.MDMPlatformsCounts{
MacOS: macOS.Verified,
Windows: windows.Verified,
},
Verifying: fleet.MDMPlatformsCounts{
MacOS: macOS.Verifying,
Windows: windows.Verifying,
},
ActionRequired: fleet.MDMPlatformsCounts{
MacOS: macOS.ActionRequired,
Windows: windows.ActionRequired,
},
Enforcing: fleet.MDMPlatformsCounts{
MacOS: macOS.Enforcing,
Windows: windows.Enforcing,
},
Failed: fleet.MDMPlatformsCounts{
MacOS: macOS.Failed,
Windows: windows.Failed,
},
RemovingEnforcement: fleet.MDMPlatformsCounts{
MacOS: macOS.RemovingEnforcement,
Windows: windows.RemovingEnforcement,
},
}, nil
}

View file

@ -150,13 +150,13 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T
}
}
if payload.MDM.MacOSSettings != nil {
if !appCfg.MDM.EnabledAndConfigured && payload.MDM.MacOSSettings.EnableDiskEncryption {
if payload.MDM.EnableDiskEncryption.Valid {
macOSDiskEncryptionUpdated = team.Config.MDM.EnableDiskEncryption != payload.MDM.EnableDiskEncryption.Value
if macOSDiskEncryptionUpdated && !appCfg.MDM.EnabledAndConfigured {
return nil, fleet.NewInvalidArgumentError("macos_settings.enable_disk_encryption",
`Couldn't update macos_settings because MDM features aren't turned on in Fleet. Use fleetctl generate mdm-apple and then fleet serve with mdm configuration to turn on MDM features.`)
}
macOSDiskEncryptionUpdated = team.Config.MDM.MacOSSettings.EnableDiskEncryption != payload.MDM.MacOSSettings.EnableDiskEncryption
team.Config.MDM.MacOSSettings.EnableDiskEncryption = payload.MDM.MacOSSettings.EnableDiskEncryption
team.Config.MDM.EnableDiskEncryption = payload.MDM.EnableDiskEncryption.Value
}
if payload.MDM.MacOSSetup != nil {
@ -225,7 +225,7 @@ func (svc *Service) ModifyTeam(ctx context.Context, teamID uint, payload fleet.T
}
if macOSDiskEncryptionUpdated {
var act fleet.ActivityDetails
if team.Config.MDM.MacOSSettings.EnableDiskEncryption {
if team.Config.MDM.EnableDiskEncryption {
act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &team.ID, TeamName: &team.Name}
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &team.ID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "enable team filevault and escrow")
@ -802,6 +802,17 @@ func (svc *Service) createTeamFromSpec(
`Couldn't update macos_setup because MDM features aren't turned on in Fleet. Use fleetctl generate mdm-apple and then fleet serve with mdm configuration to turn on MDM features.`))
}
}
enableDiskEncryption := spec.MDM.EnableDiskEncryption.Value
if !spec.MDM.EnableDiskEncryption.Valid {
if de := macOSSettings.DeprecatedEnableDiskEncryption; de != nil {
enableDiskEncryption = *de
}
}
if enableDiskEncryption && !defaults.MDM.AtLeastOnePlatformEnabledAndConfigured() {
return nil, ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("mdm",
`Couldn't edit enable_disk_encryption. Neither macOS MDM nor Windows is turned on. Visit https://fleetdm.com/docs/using-fleet to learn how to turn on MDM.`))
}
if dryRun {
return &fleet.Team{Name: spec.Name}, nil
@ -813,9 +824,10 @@ func (svc *Service) createTeamFromSpec(
AgentOptions: agentOptions,
Features: features,
MDM: fleet.TeamMDM{
MacOSUpdates: spec.MDM.MacOSUpdates,
MacOSSettings: macOSSettings,
MacOSSetup: macOSSetup,
EnableDiskEncryption: enableDiskEncryption,
MacOSUpdates: spec.MDM.MacOSUpdates,
MacOSSettings: macOSSettings,
MacOSSetup: macOSSetup,
},
},
Secrets: secrets,
@ -824,7 +836,7 @@ func (svc *Service) createTeamFromSpec(
return nil, err
}
if macOSSettings.EnableDiskEncryption {
if enableDiskEncryption && defaults.MDM.EnabledAndConfigured {
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &tm.ID); err != nil {
return nil, ctxerr.Wrap(ctx, err, "enable team filevault and escrow")
}
@ -871,11 +883,23 @@ func (svc *Service) editTeamFromSpec(
team.Config.MDM.MacOSUpdates = spec.MDM.MacOSUpdates
}
oldMacOSDiskEncryption := team.Config.MDM.MacOSSettings.EnableDiskEncryption
oldMacOSDiskEncryption := team.Config.MDM.EnableDiskEncryption
if err := svc.applyTeamMacOSSettings(ctx, spec, &team.Config.MDM.MacOSSettings); err != nil {
return err
}
newMacOSDiskEncryption := team.Config.MDM.MacOSSettings.EnableDiskEncryption
// 1. if the spec has the new setting, use that
// 2. else if the spec has the deprecated setting, use that
// 3. otherwise, leave the setting untouched
if spec.MDM.EnableDiskEncryption.Valid {
team.Config.MDM.EnableDiskEncryption = spec.MDM.EnableDiskEncryption.Value
} else if de := team.Config.MDM.MacOSSettings.DeprecatedEnableDiskEncryption; de != nil {
team.Config.MDM.EnableDiskEncryption = *de
}
if team.Config.MDM.EnableDiskEncryption && !appCfg.MDM.AtLeastOnePlatformEnabledAndConfigured() {
return ctxerr.Wrap(ctx, fleet.NewInvalidArgumentError("mdm",
`Couldn't edit enable_disk_encryption. Neither macOS MDM nor Windows is turned on. Visit https://fleetdm.com/docs/using-fleet to learn how to turn on MDM.`))
}
oldMacOSSetup := team.Config.MDM.MacOSSetup
if spec.MDM.MacOSSetup.MacOSSetupAssistant.Set || spec.MDM.MacOSSetup.BootstrapPackage.Set {
@ -925,9 +949,9 @@ func (svc *Service) editTeamFromSpec(
return err
}
}
if oldMacOSDiskEncryption != newMacOSDiskEncryption {
if appCfg.MDM.EnabledAndConfigured && oldMacOSDiskEncryption != team.Config.MDM.EnableDiskEncryption {
var act fleet.ActivityDetails
if team.Config.MDM.MacOSSettings.EnableDiskEncryption {
if team.Config.MDM.EnableDiskEncryption {
act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &team.ID, TeamName: &team.Name}
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &team.ID); err != nil {
return ctxerr.Wrap(ctx, err, "enable team filevault and escrow")
@ -982,7 +1006,7 @@ func (svc *Service) applyTeamMacOSSettings(ctx context.Context, spec *fleet.Team
}
if (setFields["custom_settings"] && len(applyUpon.CustomSettings) > 0) ||
(setFields["enable_disk_encryption"] && applyUpon.EnableDiskEncryption) {
(setFields["enable_disk_encryption"] && *applyUpon.DeprecatedEnableDiskEncryption) {
field := "custom_settings"
if !setFields["custom_settings"] {
field = "enable_disk_encryption"
@ -1016,8 +1040,8 @@ func unmarshalWithGlobalDefaults(b *json.RawMessage) (fleet.Features, error) {
func (svc *Service) updateTeamMDMAppleSettings(ctx context.Context, tm *fleet.Team, payload fleet.MDMAppleSettingsPayload) error {
var didUpdate, didUpdateMacOSDiskEncryption bool
if payload.EnableDiskEncryption != nil {
if tm.Config.MDM.MacOSSettings.EnableDiskEncryption != *payload.EnableDiskEncryption {
tm.Config.MDM.MacOSSettings.EnableDiskEncryption = *payload.EnableDiskEncryption
if tm.Config.MDM.EnableDiskEncryption != *payload.EnableDiskEncryption {
tm.Config.MDM.EnableDiskEncryption = *payload.EnableDiskEncryption
didUpdate = true
didUpdateMacOSDiskEncryption = true
}
@ -1029,7 +1053,7 @@ func (svc *Service) updateTeamMDMAppleSettings(ctx context.Context, tm *fleet.Te
}
if didUpdateMacOSDiskEncryption {
var act fleet.ActivityDetails
if tm.Config.MDM.MacOSSettings.EnableDiskEncryption {
if tm.Config.MDM.EnableDiskEncryption {
act = fleet.ActivityTypeEnabledMacosDiskEncryption{TeamID: &tm.ID, TeamName: &tm.Name}
if err := svc.MDMAppleEnableFileVaultAndEscrow(ctx, &tm.ID); err != nil {
return ctxerr.Wrap(ctx, err, "enable team filevault and escrow")

View file

@ -12,6 +12,7 @@ const DEFAULT_CONFIG_MOCK: IConfig = {
live_query_disabled: false,
enable_analytics: true,
deferred_save_host: false,
query_reports_disabled: false,
},
smtp_settings: {
enable_smtp: false,
@ -125,6 +126,7 @@ const DEFAULT_CONFIG_MOCK: IConfig = {
},
fleet_desktop: { transparency_url: "https://fleetdm.com/transparency" },
mdm: {
enable_disk_encryption: false,
windows_enabled_and_configured: true,
apple_bm_default_team: "Apples",
apple_bm_enabled_and_configured: true,

View file

@ -1,7 +1,7 @@
import { IHost } from "interfaces/host";
import { IHostMacMdmProfile } from "interfaces/mdm";
import { IHostMdmProfile } from "interfaces/mdm";
const DEFAULT_HOST_PROFILE_MOCK: IHostMacMdmProfile = {
const DEFAULT_HOST_PROFILE_MOCK: IHostMdmProfile = {
profile_id: 1,
name: "Test Profile",
operation_type: "install",
@ -10,8 +10,8 @@ const DEFAULT_HOST_PROFILE_MOCK: IHostMacMdmProfile = {
};
export const createMockHostMacMdmProfile = (
overrides?: Partial<IHostMacMdmProfile>
): IHostMacMdmProfile => {
overrides?: Partial<IHostMdmProfile>
): IHostMdmProfile => {
return { ...DEFAULT_HOST_PROFILE_MOCK, ...overrides };
};
@ -53,6 +53,11 @@ const DEFAULT_HOST_MOCK: IHost = {
enrollment_status: "Off",
server_url: "https://www.example.com/1",
profiles: [],
os_settings: {
disk_encryption: {
status: null,
},
},
macos_settings: {
disk_encryption: null,
action_required: null,

View file

@ -36,6 +36,11 @@ const DEFAULT_HOST_MDM_DATA: IHostMdmData = {
name: "MDM Solution",
id: 1,
profiles: [],
os_settings: {
disk_encryption: {
status: "verified",
},
},
macos_settings: {
disk_encryption: null,
action_required: null,

View file

@ -12,6 +12,7 @@ const DEFAULT_QUERY_MOCK: ISchedulableQuery = {
author_name: "Test User",
author_email: "test@example.com",
observer_can_run: false,
discard_data: false,
interval: 300,
packs: [],
team_id: null,

View file

@ -0,0 +1,331 @@
import { IQueryReport } from "interfaces/query_report";
const DEFAULT_QUERY_REPORT_MOCK: IQueryReport = {
query_id: 31,
results: [
{
host_id: 1,
host_name: "foo",
last_fetched: "2021-01-19T17:08:31Z",
columns: {
model: "Razer Viper",
vendor: "Razer",
model_id: "0078",
},
},
{
host_id: 1,
host_name: "foo",
last_fetched: "2021-01-19T17:08:31Z",
columns: {
model: "USB Keyboard",
vendor: "VIA Labs, Inc.",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "USB Reciever",
vendor: "Logitech",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "USB Keyboard",
vendor: "Logitech",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "YubiKey OTP+FIDO+CCID",
vendor: "Yubico",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "Lenovo USB Optical Mouse",
vendor: "PixArt",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "Lenovo Traditional USB Keyboard",
vendor: "Lenovo",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "Display Audio",
vendor: "Bose",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "USB-C Digital AV Multiport Adapter",
vendor: "Apple, Inc.",
model_id: "1460",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "USB Reciever",
vendor: "Logitech",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "USB-C Digital AV Multiport Adapter",
vendor: "Apple Inc.",
model_id: "1460",
},
},
{
host_id: 2,
host_name: "bar",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "USB Reciever",
vendor: "Logitech",
},
},
{
host_id: 3,
host_name: "zoo",
last_fetched: "2022-04-09T17:20:00Z",
columns: {
model: "Logitech Webcam C925e",
model_id: "085b",
},
},
{
host_id: 3,
host_name: "zoo",
last_fetched: "2022-04-09T17:20:00Z",
columns: {
model: "Display Audio",
vendor: "Apple Inc.",
},
},
{
host_id: 3,
host_name: "zoo",
last_fetched: "2022-04-09T17:20:00Z",
columns: {
model: "Ambient Light Sensor",
vendor: "Apple Inc.",
},
},
{
host_id: 3,
host_name: "zoo",
last_fetched: "2022-04-09T17:20:00Z",
columns: {
model: "DELL Laser Mouse",
model_id: "4d51",
},
},
{
host_id: 7,
host_name: "Rachel's Magnificent Testing Computer of All Computers",
last_fetched: "2023-09-21T19:03:30Z",
columns: {
model: "AppleUSBVHCIBCE Root Hub Simulation",
vendor: "Apple Inc.",
},
},
{
host_id: 7,
host_name: "Rachel's Magnificent Testing Computer of All Computers",
last_fetched: "2023-09-21T19:03:30Z",
columns: {
model: "QuickFire Rapid keyboard",
vendor: "CM Storm",
model_id: "0004",
},
},
{
host_id: 7,
host_name: "Rachel's Magnificent Testing Computer of All Computers",
last_fetched: "2023-09-21T19:03:30Z",
columns: {
model: "Lenovo USB Optical Mouse",
vendor: "Lenovo",
},
},
{
host_id: 7,
host_name: "Rachel's Magnificent Testing Computer of All Computers",
last_fetched: "2023-09-21T19:03:30Z",
columns: {
model: "YubiKey FIDO+CCID",
vendor: "Yubico",
},
},
{
host_id: 4,
host_name: "car",
last_fetched: "2023-01-14T12:40:30Z",
columns: {
model: "USB2.0 Hub",
vendor: "Apple Inc.",
},
},
{
host_id: 8,
host_name: "apple man",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "FaceTime HD Camera (Display)",
vendor: "Apple Inc.",
model_id: "1112",
},
},
{
host_id: 8,
host_name: "apple man",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "Apple Internal Keyboard / Trackpad",
model_id: "027e",
vendor: "Apple Inc.",
},
},
{
host_id: 8,
host_name: "apple man",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "Apple Thunderbolt Display",
vendor: "Apple Inc.",
model_id: "9227",
},
},
{
host_id: 8,
host_name: "apple man",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "AppleUSBXHCI Root Hub Simulation",
vendor: "Apple Inc.",
model_id: "8007",
},
},
{
host_id: 8,
host_name: "apple man",
last_fetched: "2021-01-19T17:20:00Z",
columns: {
model: "Apple T2 Controller",
vendor: "Apple Inc.",
model_id: "8233",
},
},
{
host_id: 5,
host_name: "choo",
last_fetched: "2023-09-03T03:40:30Z",
columns: {
model: "4-Port USB 2.0 Hub",
vendor: "Generic",
},
},
{
host_id: 5,
host_name: "choo",
last_fetched: "2023-09-03T03:40:30Z",
columns: {
model: "USB 10_100_1000 LAN",
vendor: "Realtek",
},
},
{
host_id: 5,
host_name: "choo",
last_fetched: "2023-09-03T03:40:30Z",
columns: {
model: "Display Audio",
vendor: "Apple Inc.",
},
},
{
host_id: 5,
host_name: "choo",
last_fetched: "2023-09-03T03:40:30Z",
columns: {
model: "USB Mouse",
vendor: "Razor",
},
},
{
host_id: 5,
host_name: "choo",
last_fetched: "2023-09-03T03:40:30Z",
columns: {
model: "USB Audio",
vendor: "Apple, Inc.",
},
},
{
host_id: 6,
host_name: "moo",
last_fetched: "2023-09-20T07:02:34Z",
columns: {
model: "Display Audio",
vendor: "Apple Inc.",
},
},
{
host_id: 6,
host_name: "moo",
last_fetched: "2023-09-20T07:02:34Z",
columns: {
model: "USB Reciever",
vendor: "Logitech",
},
},
{
host_id: 6,
host_name: "moo",
last_fetched: "2023-09-20T07:02:34Z",
columns: {
model: "LG Monitor Controls",
vendor: "LG Electronics Inc.",
model_id: "9a39",
},
},
],
};
const createMockQueryReport = (
overrides?: Partial<IQueryReport>
): IQueryReport => {
return { ...DEFAULT_QUERY_REPORT_MOCK, ...overrides };
};
export default createMockQueryReport;

View file

@ -20,6 +20,7 @@ const DEFAULT_SCHEDULABLE_QUERY_MOCK: ISchedulableQuery = {
author_name: "Test User",
author_email: "test@example.com",
observer_can_run: false,
discard_data: false,
packs: [],
stats: {
system_time_p50: 28.1053,

View file

@ -57,7 +57,6 @@
&__container {
align-self: center;
justify-content: center;
margin: 0;
margin-bottom: 20px;
min-height: 155px;
max-width: none;

View file

@ -3,6 +3,7 @@ import classNames from "classnames";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
import { IconNames } from "components/icons";
const baseClass = "info-banner";
@ -10,29 +11,37 @@ export interface IInfoBannerProps {
children?: React.ReactNode;
className?: string;
/** default light purple */
color?: "yellow" | "grey";
color?: "purple" | "purple-bold-border" | "yellow" | "grey";
/** default 4px */
borderRadius?: "large" | "xlarge";
pageLevel?: boolean;
/** cta and link are mutually exclusive */
cta?: JSX.Element;
/** closable and link are mutually exclusive */
closable?: boolean;
link?: string;
icon?: IconNames;
}
const InfoBanner = ({
children,
className,
color,
color = "purple",
borderRadius,
pageLevel,
cta,
closable,
link,
icon,
}: IInfoBannerProps): JSX.Element => {
const wrapperClasses = classNames(
baseClass,
`${baseClass}__${color}`,
{
[`${baseClass}__${color}`]: !!color,
[`${baseClass}__border-radius-${borderRadius}`]: !!borderRadius,
[`${baseClass}__page-banner`]: !!pageLevel,
[`${baseClass}__icon`]: !!icon,
},
className
);
@ -42,6 +51,7 @@ const InfoBanner = ({
const content = (
<>
<div className={`${baseClass}__info`}>{children}</div>
{(cta || closable) && (
<div className={`${baseClass}__cta`}>
{cta}

View file

@ -5,11 +5,19 @@
padding: $pad-medium;
border-radius: $border-radius;
border: 1px solid $ui-vibrant-blue-50;
background-color: $ui-vibrant-blue-10;
font-size: $x-small;
font-weight: $regular;
color: $core-fleet-black;
&__purple {
background-color: $ui-vibrant-blue-10;
}
&__purple-bold-border {
background-color: $ui-vibrant-blue-10;
border-color: $core-vibrant-blue;
}
&__yellow {
background-color: $ui-yellow-banner;
border-color: $ui-yellow-banner-outline;
@ -26,6 +34,20 @@
width: auto;
}
&__border-radius-large {
border-radius: $border-radius-large;
}
&__border-radius-xlarge {
border-radius: $border-radius-xlarge;
}
&__info {
display: flex;
flex-direction: column;
gap: $pad-small;
}
&__cta {
display: flex;
align-items: center;
@ -51,4 +73,8 @@
}
}
}
p {
margin: 0;
}
}

View file

@ -12,7 +12,7 @@ import {
ISelectLabel,
ISelectTeam,
ISelectTargetsEntity,
ISelectedTargets,
ISelectedTargetsForApi,
} from "interfaces/target";
import { ITeam } from "interfaces/team";
@ -48,7 +48,9 @@ interface ISelectTargetsProps {
targetedTeams: ITeam[];
goToQueryEditor: () => void;
goToRunQuery: () => void;
setSelectedTargets: React.Dispatch<React.SetStateAction<ITarget[]>>;
setSelectedTargets: // TODO: Refactor policy targets to streamline selectedTargets/selectedTargetsByType
| React.Dispatch<React.SetStateAction<ITarget[]>> // Used for policies page level useState hook
| ((value: ITarget[]) => void); // Used for queries app level QueryContext
setTargetedHosts: React.Dispatch<React.SetStateAction<IHost[]>>;
setTargetedLabels: React.Dispatch<React.SetStateAction<ILabel[]>>;
setTargetedTeams: React.Dispatch<React.SetStateAction<ITeam[]>>;
@ -65,7 +67,7 @@ interface ITargetsQueryKey {
scope: string;
query_id?: number | null;
query?: string | null;
selected?: ISelectedTargets | null;
selected?: ISelectedTargetsForApi | null;
}
const DEBOUNCE_DELAY = 500;
@ -379,12 +381,22 @@ const SelectTargets = ({
}
const { targets_count: total, targets_online: online } = counts;
const onlinePercentage = total > 0 ? Math.round((online / total) * 100) : 0;
const onlinePercentage = () => {
if (total === 0) {
return 0;
}
// If at least 1 host is online, displays <1% instead of 0%
const roundPercentage =
Math.round((online / total) * 100) === 0
? "<1"
: Math.round((online / total) * 100) === 0;
return roundPercentage;
};
return (
<>
<span>{total}</span>&nbsp;host{total > 1 ? `s` : ``} targeted&nbsp; (
{onlinePercentage}
{onlinePercentage()}
%&nbsp;
<TooltipWrapper
tipContent={`Hosts are online if they<br /> have recently checked <br />into Fleet.`}

View file

@ -79,4 +79,7 @@
overflow: auto;
}
}
.input-icon-field__icon {
top: 34px; // Override styling to include label header
}
}

View file

@ -23,7 +23,10 @@ interface IStatusIndicatorWithIconProps {
tooltipText: string | JSX.Element;
position?: "top" | "bottom";
};
layout?: "horizontal" | "vertical";
className?: string;
/** Classname to add to the value text */
valueClassName?: string;
}
const statusIconNameMapping: Record<IndicatorStatus, IconNames> = {
@ -38,13 +41,18 @@ const StatusIndicatorWithIcon = ({
status,
value,
tooltip,
layout = "horizontal",
className,
valueClassName,
}: IStatusIndicatorWithIconProps) => {
const classNames = classnames(baseClass, className);
const id = `status-${uniqueId()}`;
const valueClasses = classnames(`${baseClass}__value`, valueClassName, {
[`${baseClass}__value-vertical`]: layout === "vertical",
});
const valueContent = (
<span className={`${baseClass}__value`}>
<span className={valueClasses}>
<Icon name={statusIconNameMapping[status]} />
<span>{value}</span>
</span>

View file

@ -1,4 +1,5 @@
.status-indicator-with-icon {
// default layout is horizontal
&__value {
display: inline-flex;
align-items: center;
@ -8,4 +9,10 @@
margin-right: $pad-xsmall;
}
}
// overrides for different layout
&__value-vertical {
flex-direction: column;
gap: $pad-xsmall;
}
}

View file

@ -8,6 +8,11 @@ const DefaultColumnFilter = ({
}: FilterProps<TableInstance>): JSX.Element => {
const { setFilter } = column;
// Remove last_fetched filter per design as it is confusing to filter by a non-displayed date-string
if (column.id === "last_fetched") {
return <></>;
}
return (
<div className={"filter-cell"}>
<SearchField

View file

@ -6,6 +6,7 @@ import * as DOMPurify from "dompurify";
interface ITooltipWrapperProps {
children: string | JSX.Element;
tipContent: string;
/** Default: bottom */
position?: "top" | "bottom";
isDelayed?: boolean;
className?: string;

View file

@ -341,9 +341,7 @@ $base-class: "button";
}
&--disabled {
opacity: 0.5;
filter: grayscale(0.5);
cursor: default;
@include disabled;
&:hover,
&:focus {

View file

@ -1,10 +1,12 @@
import React from "react";
import { COLORS, Colors } from "styles/var/colors";
import { IconSizes, ICON_SIZES } from "styles/var/icon_sizes";
interface IChevronProps {
color?: Colors;
/** Default direction "down" */
direction?: "up" | "down" | "left" | "right";
size: IconSizes;
}
const SVG_PATH = {
@ -17,11 +19,12 @@ const SVG_PATH = {
const Chevron = ({
color = "core-fleet-black",
direction = "down",
size = "medium",
}: IChevronProps) => {
return (
<svg
width="16"
height="16"
width={ICON_SIZES[size]}
height={ICON_SIZES[size]}
fill="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"

View file

@ -0,0 +1,254 @@
import React from "react";
const CollectingResults = () => {
return (
<svg
width="240"
height="126"
fill="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 240 126"
>
<g clipPath="url(#a)">
<path
d="M109.214 120.128c26.769-13.44 35.513-50.12 19.53-81.927C112.761 6.394 78.104-8.496 51.335 4.945c-26.768 13.44-35.512 50.12-19.53 81.927 15.984 31.807 50.64 46.697 77.409 33.256Z"
fill="#F1F1FD"
/>
<path
d="M123.697 16.088a14.505 14.505 0 0 1 10.124 4.55 14.49 14.49 0 0 1 3.94 10.374 1.478 1.478 0 0 0 2.475 1.09c.283-.26.454-.62.475-1.004a17.439 17.439 0 0 0-7.27-14.696 17.454 17.454 0 0 0-9.657-3.26 1.472 1.472 0 0 0-1.388.87 1.466 1.466 0 0 0-.034 1.127 1.475 1.475 0 0 0 1.335.95Zm22.334 16.65a1.48 1.48 0 0 0 1.055-.4 1.466 1.466 0 0 0 .463-1.03 24.47 24.47 0 0 0-.309-4.65 24.218 24.218 0 0 0-3.296-8.828 24.288 24.288 0 0 0-19.959-11.517 1.477 1.477 0 0 0-1.094 2.474c.26.283.621.454 1.005.475a21.35 21.35 0 0 1 14.901 6.693 21.332 21.332 0 0 1 5.8 15.265 1.469 1.469 0 0 0 .87 1.39c.177.08.368.123.562.128h.002Z"
fill="#D7DAF5"
/>
<path
d="M185.292 85.93v6.313h-19.379v-6.314a.937.937 0 0 1 .936-.935h17.507a.935.935 0 0 1 .936.935Z"
fill="#F1F1FD"
/>
<path
d="M196.958 114.897V89.31a1.87 1.87 0 0 0-1.871-1.87h-65.532a1.87 1.87 0 0 0-1.871 1.87v25.587a1.87 1.87 0 0 0 1.871 1.871h65.532a1.87 1.87 0 0 0 1.871-1.871Z"
fill="#D7DAF5"
/>
<path
d="M163.092 113.824v-8.418a.468.468 0 0 0-.468-.468h-3.743a.468.468 0 0 0-.468.468v8.418c0 .258.21.468.468.468h3.743c.258 0 .468-.21.468-.468Z"
fill="#F1F1FD"
/>
<path
d="M155.318 112.587V91.621c0-1.147-.93-2.077-2.077-2.077h-21.375c-1.147 0-2.077.93-2.077 2.077v20.966c0 1.147.93 2.076 2.077 2.076h21.375a2.076 2.076 0 0 0 2.077-2.076Z"
fill="#E6E6F7"
/>
<path
d="M181.722 112.966c6.002 0 10.867-4.863 10.867-10.862s-4.865-10.862-10.867-10.862c-6.001 0-10.866 4.863-10.866 10.862s4.865 10.862 10.866 10.862Z"
fill="#fff"
/>
<path
d="M186.333 106.556v-8.907a.935.935 0 0 0-1.871 0v8.907a.936.936 0 1 0 1.871 0ZM182.59 106.556v-8.907a.935.935 0 0 0-1.871 0v8.907a.936.936 0 1 0 1.871 0ZM178.847 106.556v-8.907a.935.935 0 0 0-1.871 0v8.907a.936.936 0 1 0 1.871 0Z"
fill="#B0B2E7"
/>
<path
d="M238.012 116.625a1.578 1.578 0 0 1-.349-.035c-14.607-2.944-26.523-4.641-44.199-4.641a1.754 1.754 0 1 1 0-3.508c17.975 0 30.074 1.728 44.901 4.712a1.755 1.755 0 0 1 1.397 1.893 1.76 1.76 0 0 1-1.743 1.579h-.007Z"
fill="#D7DAF5"
/>
<path
d="m78.157 120.042-50.855 4.677V74.677l50.855-2.105v47.47Z"
fill="#E6E6F7"
/>
<path
d="m45.776 109.065 13.945-.905-1.448-34.76 6.882-.36 2.897 47.792-40.836 3.873 18.56-15.64Z"
fill="#D7DAF5"
/>
<path
d="m38.328 123-1.048-.936c.025-.011 2.793-1.218 5.418-4.842 4.405-6.08 5.708-14.145 5.455-19.877-.253-5.731-3.626-12.201-9.357-17.5-3.38-3.145-11.098-5.08-11.131-5.086-.033-.007 4.74-.286 6.248-.363 1.362.622 4.595 2.285 6.429 3.975 6.082 5.613 8.95 12.862 9.215 18.888.264 6.026-.41 14.498-5.11 20.917-1.92 2.626-3.897 4.061-5.02 4.735l-1.1.089Z"
fill="#D7DAF5"
/>
<path
d="M27.216 124.705c11.505 0 20.832-11.192 20.832-24.998 0-13.806-9.327-24.997-20.832-24.997S6.384 85.9 6.384 99.707s9.327 24.998 20.832 24.998Z"
fill="#fff"
/>
<path
d="M27.216 122.81c10.633 0 19.253-10.343 19.253-23.103 0-12.76-8.62-23.103-19.253-23.103-10.633 0-19.253 10.343-19.253 23.103 0 12.76 8.62 23.103 19.253 23.103Z"
fill="#F1F1FD"
/>
<path
d="M27.216 120.841c9.726 0 17.61-9.462 17.61-21.134s-7.884-21.134-17.61-21.134c-9.726 0-17.61 9.462-17.61 21.134s7.884 21.134 17.61 21.134Z"
fill="#fff"
/>
<path
d="M27.216 119.078c8.916 0 16.144-8.672 16.144-19.37 0-10.7-7.228-19.372-16.144-19.372-8.916 0-16.144 8.673-16.144 19.371 0 10.699 7.228 19.371 16.144 19.371Z"
fill="#F1F1FD"
/>
<path
d="M27.216 116.78c7.858 0 14.228-7.644 14.228-17.073s-6.37-17.073-14.228-17.073-14.228 7.644-14.228 17.073 6.37 17.073 14.228 17.073Z"
fill="#fff"
/>
<path
d="M27.216 101.505c.828 0 1.5-.805 1.5-1.798s-.672-1.798-1.5-1.798-1.5.805-1.5 1.798.672 1.798 1.5 1.798Z"
fill="#B0B2E7"
/>
<path
d="m45.814 123-.37-.884c.026-.012 2.793-1.218 5.416-4.843 4.407-6.08 5.032-14.208 4.779-19.947-.253-5.738-1.755-13.724-7.486-19.022-3.387-3.136-7.797-4.158-7.83-4.165-.032-.007 2.293-.091 3.802-.166a18.424 18.424 0 0 1 4.982 3.302c6.083 5.612 7.666 13.974 7.93 19.99.265 6.017-.409 14.499-5.108 20.918-1.92 2.626-3.898 4.061-5.02 4.735l-1.095.082Z"
fill="#D7DAF5"
/>
<path
d="m51.615 122.462-.234-.578c.021-.011 2.2-1.218 4.267-4.842 3.472-6.08 3.963-14.209 3.764-19.947-.199-5.738-1.382-13.724-5.892-19.023a14.248 14.248 0 0 0-6.17-4.165s1.807-.09 2.995-.166a14.737 14.737 0 0 1 3.928 3.302c4.786 5.612 6.038 13.974 6.246 19.991.208 6.017-.323 14.498-4.024 20.917-1.513 2.626-2.9 3.742-3.785 4.42-.416.04-1.095.091-1.095.091Z"
fill="#D7DAF5"
/>
<path
d="m23.005 99.707.9-.327c-5.953 0-11.68 5.144-11.68 11.102v10.289a3.491 3.491 0 0 1-3.495 3.492H0"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
<path
d="M25.11 99.707h.789c-5.954 0-11.568 4.834-11.568 10.785v10.289a3.486 3.486 0 0 1-2.158 3.226 3.505 3.505 0 0 1-1.337.265h-8.73"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
<path
d="M27.216 99.707a10.781 10.781 0 0 0-10.78 10.775v10.289a3.493 3.493 0 0 1-3.495 3.492h-8.73"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
<path
d="m70.225 65.3-5.547.19-.089-20.897 5.547-.119.089 20.826Z"
fill="#D7DAF5"
/>
<path
d="m83.854 125.404-4.396.402a14.325 14.325 0 0 1-14.427-8.467 14.309 14.309 0 0 1-1.22-5.783V65.894a.702.702 0 0 1 .685-.702l19.358-.451v60.663Z"
fill="#D7DAF5"
/>
<path
d="m131.515 64.13-61.924 1.125-.09-21.363 61.923.816.091 19.423Z"
fill="#D7DAF5"
/>
<path
d="m82.5 56.283-5.536.072a1.997 1.997 0 0 1-2.02-1.99v-.92a1.993 1.993 0 0 1 2.006-2l5.533.033a1.996 1.996 0 0 1 1.984 1.987v.816a1.992 1.992 0 0 1-1.968 2.002Z"
fill="#B0B2E7"
/>
<path
d="m121.59 121.333-39.245 4.396a11.72 11.72 0 0 1-9.11-2.908 11.71 11.71 0 0 1-3.904-8.726V65.134l61.951-1.155a.705.705 0 0 1 .659.43.701.701 0 0 1 .054.271v45.033a11.698 11.698 0 0 1-10.405 11.62Z"
fill="#fff"
/>
<path
d="m81.921 44.02-17.22.63a.701.701 0 0 1-.727-.702l-.037-10.338c-.029-7.633 6.126-13.616 13.762-13.668l4.134-.026-1.736 3.508-5.977 5.081 2.987 12.038 4.814 3.478Z"
fill="#D7DAF5"
/>
<path
d="M74.09 22.229v3.04l39.38 1.183a6.519 6.519 0 0 1 6.274 6.618l-.047 2.787a5.477 5.477 0 0 1-5.528 5.378l-40.08-.194v1.085h52.883v-16.79L74.089 22.23Z"
fill="#D7DAF5"
/>
<path
d="m121.976 21.855-40.195-1.948a11.89 11.89 0 0 0-11.5 7.186 11.876 11.876 0 0 0-.962 4.679v12.627l61.958.468a.702.702 0 0 0 .702-.702V32.36a10.523 10.523 0 0 0-10.003-10.504Zm4.559 12.26a7.268 7.268 0 0 1-7.306 7.275l-34.856-.162a8.636 8.636 0 0 1-8.595-8.628v-1.523a6.928 6.928 0 0 1 4.455-6.472 6.938 6.938 0 0 1 2.73-.454l37.045 1.373a6.78 6.78 0 0 1 6.529 6.765l-.002 1.826Z"
fill="#fff"
/>
<path
d="m126.441 111.109-46.035 5.685a6.245 6.245 0 0 1-4.893-1.518 6.23 6.23 0 0 1-2.102-4.67V76.117h53.03v34.992Z"
fill="#D7DAF5"
/>
<path
d="m126.182 111.074-45.325 4.859a5.788 5.788 0 0 1-5.855-3.277 5.79 5.79 0 0 1-.555-2.302l-1.03-33.327a5.844 5.844 0 0 1 5.653-6.035l46.059-1.705a4.958 4.958 0 0 1 5.147 4.786l1.052 31.115a5.712 5.712 0 0 1-5.146 5.886Z"
fill="#fff"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="m125.992 97.92-46.454 3.821a3.59 3.59 0 0 1-2.682-.897 3.587 3.587 0 0 1-1.197-2.561l-.688-21.565a4.054 4.054 0 0 1 3.9-4.18l46.532-1.806a3.664 3.664 0 0 1 3.482 2.158c.198.442.307.919.319 1.403l.508 19.477a4.05 4.05 0 0 1-3.72 4.15Z"
fill="#F1F1FD"
/>
<path
d="m126.189 96.45-46.506 3.809a2.503 2.503 0 0 1-1.881-.63 2.51 2.51 0 0 1-.838-1.797L76.42 79.11a2.68 2.68 0 0 1 2.574-2.761l46.929-1.913a2.005 2.005 0 0 1 2.091 1.964l.384 17.604a2.404 2.404 0 0 1-2.208 2.446Z"
fill="#F1F1FD"
/>
<path
d="M99.03 53.399v1.328h-3.676V53.4h3.677Zm-3.1-2.845v7.166h-1.728v-7.166h1.728Zm4.262 0v7.166H98.47v-7.166h1.722Zm6.634 5.837v1.329h-3.819v-1.329h3.819Zm-3.204-5.837v7.166h-1.727v-7.166h1.727Zm2.712 2.845v1.284h-3.327V53.4h3.327Zm.507-2.845v1.334h-3.834v-1.334h3.834Zm6.034 5.837v1.329h-3.623v-1.329h3.623Zm-3.008-5.837v7.166h-1.727v-7.166h1.727Zm9.076 5.837v1.329h-3.623v-1.329h3.623Zm-3.007-5.837v7.166h-1.728v-7.166h1.728Zm10.089 3.44v.29c0 .549-.077 1.04-.232 1.477-.15.433-.365.804-.644 1.112-.279.306-.609.54-.99.704-.38.161-.8.241-1.26.241-.462 0-.886-.08-1.269-.24a2.915 2.915 0 0 1-.995-.705 3.266 3.266 0 0 1-.649-1.112 4.499 4.499 0 0 1-.227-1.477v-.29c0-.548.076-1.04.227-1.476a3.26 3.26 0 0 1 .644-1.113c.279-.308.609-.543.99-.704a3.198 3.198 0 0 1 1.27-.246c.459 0 .879.082 1.26.246.383.161.715.396.994.704.279.305.495.676.649 1.113.155.436.232.928.232 1.476Zm-1.752.29v-.3a4.19 4.19 0 0 0-.094-.935 2.071 2.071 0 0 0-.266-.684 1.18 1.18 0 0 0-1.023-.556 1.143 1.143 0 0 0-1.029.556 2.138 2.138 0 0 0-.261.684c-.056.27-.084.58-.084.935v.3c0 .352.028.663.084.936.059.269.146.497.261.684.118.187.262.328.433.423.174.095.376.143.605.143.22 0 .415-.048.586-.143.171-.095.313-.236.428-.423.118-.187.207-.415.266-.684.062-.273.094-.584.094-.935ZM95.558 86.67a2.264 2.264 0 1 0 0-4.527 2.264 2.264 0 0 0 0 4.528ZM111.699 85.735a2.263 2.263 0 1 0 0-4.527 2.264 2.264 0 1 0 0 4.527Z"
fill="#B0B2E7"
/>
<path
d="m101.375 89.205 5.797-.234"
stroke="#B0B2E7"
strokeWidth="1.887"
strokeMiterlimit="10"
strokeLinecap="round"
/>
<path
d="M165.913 87.386v-1.457a.937.937 0 0 1 .936-.935h17.507a.935.935 0 0 1 .936.935v1.548"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="M131.894 87.44h63.193a1.871 1.871 0 0 1 1.871 1.87v25.585a1.871 1.871 0 0 1-1.871 1.871h-65.338"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="M131.864 89.544h21.274a2.182 2.182 0 0 1 2.18 2.18v20.753a2.178 2.178 0 0 1-2.18 2.179h-22.196M181.722 112.966c6.002 0 10.867-4.863 10.867-10.862s-4.865-10.862-10.867-10.862c-6.001 0-10.866 4.863-10.866 10.862s4.865 10.862 10.866 10.862ZM196.956 108.464c16.092.213 27.558 1.904 41.406 4.689a1.755 1.755 0 0 1 .83 3.018 1.75 1.75 0 0 1-1.524.419c-13.629-2.743-24.917-4.408-40.728-4.618M29.296 124.59l38.033-3.515M69.01 43.747a.774.774 0 0 0 .765.783l61.172.398a.98.98 0 0 0 .992-.966c0-1.87 0-6.262-.045-12.188-.03-5.144-3.534-7.716-6.012-8.902-1.201-.56-2.5-.878-3.825-.936-6.187-.299-30.998-1.508-40.795-2.06a8.657 8.657 0 0 0-1.907.103c-10.125 1.654-10.11 12.244-10.11 12.244l-.235 11.524Z"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="M79.914 19.904s-11.837-.603-15.194 9.31a14.378 14.378 0 0 0-.723 4.517c-.03 4.488-.014 8.091 0 9.822a1.103 1.103 0 0 0 1.13 1.11l4.494-.095M69.736 44.654v20.33M64.844 44.654v20.419M131.26 45.16v18.737M131.894 64.816v45.531a10.753 10.753 0 0 1-9.546 10.696l-40.558 4.599a11.371 11.371 0 0 1-8.856-2.815 11.36 11.36 0 0 1-3.795-8.479v-48.55a.828.828 0 0 1 .814-.828l61.073-1.005a.849.849 0 0 1 .868.85Z"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="M81.152 125.691c-10.595.875-17.393-5.96-17.393-14.03V65.999a.783.783 0 0 1 .744-.781l5.542-.264M26.035 74.721l37.55-1.328M27.216 124.704c11.505 0 20.832-11.191 20.832-24.997S38.72 74.71 27.216 74.71 6.384 85.9 6.384 99.707s9.327 24.997 20.832 24.997ZM119.606 41.357H84.191a8.169 8.169 0 0 1-8.162-8.166v-2.754a6.473 6.473 0 0 1 6.725-6.47l37.385 1.447a6.782 6.782 0 0 1 6.527 6.795v2.105a7.04 7.04 0 0 1-4.359 6.51 7.055 7.055 0 0 1-2.701.533Z"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="m78.649 25.278 34.912 1.11a6.426 6.426 0 0 1 6.227 6.428v3.195a5.352 5.352 0 0 1-5.303 5.353M163.092 113.824v-8.418a.468.468 0 0 0-.468-.468h-3.743a.468.468 0 0 0-.468.468v8.418c0 .258.21.468.468.468h3.743c.258 0 .468-.21.468-.468Z"
stroke="#B0B2E7"
strokeWidth=".472"
strokeMiterlimit="10"
/>
<path
d="M147.107 117.091c.261 2.609-1.423 4.289-6.054 4.289M76.927 53.472v8.797a4.977 4.977 0 0 1-4.98 4.976h-7.17c-3.4 0-8.497 2.757-8.497 6.157"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
<path
d="M79.734 53.472v8.797a4.977 4.977 0 0 1-4.98 4.976h-7.17c-3.4 0-8.497 2.757-8.497 6.157"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
<path
d="M82.307 53.472v8.797a4.977 4.977 0 0 1-4.98 4.976h-7.17c-3.4 0-8.497 2.757-8.497 6.157"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
<path
d="m140.211 121.8-4.319-.002a9.98 9.98 0 0 1-9.984-9.98v-3.566a3.564 3.564 0 0 0-3.56-3.562h-.234"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
strokeLinecap="round"
/>
<path
d="M157.707 86.156h-.708.708Zm-7.198-7.195v.707-.707Zm-28.391 29.291-.707-.001v.001h.707Zm-3.56-4.269a.707.707 0 1 0 0 1.415v-1.415Zm39.856-16.604v-1.223h-1.415v1.223h1.415Zm0-1.223a7.903 7.903 0 0 0-2.315-5.588l-1.001 1a6.487 6.487 0 0 1 1.901 4.588h1.415Zm-2.315-5.588a7.908 7.908 0 0 0-5.59-2.315v1.415c1.721 0 3.372.684 4.589 1.9l1.001-1Zm-5.59-2.315a7.905 7.905 0 0 0-5.59 2.315l1 1a6.492 6.492 0 0 1 4.59-1.9v-1.415Zm-5.59 2.315a7.9 7.9 0 0 0-2.316 5.588h1.415c0-1.72.684-3.37 1.901-4.587l-1-1.001Zm-2.316 5.588v30.6h1.415v-30.6h-1.415Zm0 30.6a5.033 5.033 0 0 1-1.476 3.561l1.001 1.001a6.452 6.452 0 0 0 1.89-4.562h-1.415Zm-1.476 3.561a5.039 5.039 0 0 1-3.562 1.475v1.415c1.711 0 3.353-.68 4.563-1.889l-1.001-1.001Zm-3.562 1.475h-5.462v1.415h5.462v-1.415Zm-5.462 0a9.279 9.279 0 0 1-6.56-2.716l-1 1.001a10.694 10.694 0 0 0 7.56 3.13v-1.415Zm-6.56-2.716a9.27 9.27 0 0 1-2.717-6.557h-1.415c0 2.835 1.126 5.553 3.132 7.558l1-1.001Zm-2.717-6.557v-4.267h-1.415v4.267h1.415Zm0-4.267c0-.561-.11-1.116-.324-1.634l-1.308.541c.144.347.217.717.217 1.092l1.415.001Zm-.324-1.634a4.288 4.288 0 0 0-.925-1.385l-1.001 1.001c.265.265.475.579.618.925l1.308-.541Zm-.925-1.385a4.272 4.272 0 0 0-1.385-.925l-.542 1.307c.346.143.661.354.926.619l1.001-1.001Zm-1.385-.925a4.26 4.26 0 0 0-1.634-.325v1.415c.375 0 .746.074 1.092.217l.542-1.307Z"
fill="#B0B2E7"
/>
<path
d="M153.543 87.379v-1.223a7.194 7.194 0 0 0-7.199-7.195h-.329c-4.492.203-7.57 4.642-6.38 8.977l7.134 25.939c.22.798.331 1.623.331 2.45v.846"
stroke="#B0B2E7"
strokeWidth="1.415"
strokeMiterlimit="10"
/>
</g>
<defs>
<clipPath id="a">
<path fill="#fff" d="M0 0h240v126H0z" />
</clipPath>
</defs>
</svg>
);
};
export default CollectingResults;

View file

@ -4,6 +4,7 @@ import ArrowInternalLink from "./ArrowInternalLink";
import CalendarCheck from "./CalendarCheck";
import Check from "./Check";
import Chevron from "./Chevron";
import CollectingResults from "./CollectingResults";
import Columns from "./Columns";
import CriticalPolicy from "./CriticalPolicy";
import Disable from "./Disable";
@ -84,6 +85,7 @@ export const ICON_MAP = {
"calendar-check": CalendarCheck,
chevron: Chevron,
check: Check,
"collecting-results": CollectingResults,
columns: Columns,
"critical-policy": CriticalPolicy,
disable: Disable,

View file

@ -1,19 +1,18 @@
import React from "react";
import PhoneHome from "../../../../../assets/images/phone-home.svg";
import EmptyTable from "components/EmptyTable/EmptyTable";
const baseClass = "awaiting-results";
const AwaitingResults = () => {
return (
<div className={baseClass}>
<img src={PhoneHome} alt="awaiting results" />
<span className={`${baseClass}__title`}>Phoning home...</span>
<p className={`${baseClass}__description`}>
There are currently no results to your query. Please wait while we talk
to more hosts.
</p>
</div>
<EmptyTable
iconName="collecting-results"
header="Phoning home..."
info=" There are currently no results to your query. Please wait while we talk
to more hosts."
className={baseClass}
/>
);
};

View file

@ -5,19 +5,4 @@
flex-direction: column;
align-items: center;
text-align: center;
img {
margin-bottom: $pad-medium;
}
&__title {
font-size: $small;
font-weight: $bold;
margin-bottom: $pad-small;
}
&__description {
font-size: $x-small;
margin: 0;
}
}

View file

@ -6,6 +6,12 @@ import { DEFAULT_QUERY } from "utilities/constants";
import { DEFAULT_OSQUERY_TABLE, IOsQueryTable } from "interfaces/osquery_table";
import { SelectedPlatformString } from "interfaces/platform";
import { QueryLoggingOption } from "interfaces/schedulable_query";
import {
DEFAULT_TARGETS,
DEFAULT_TARGETS_BY_TYPE,
ISelectedTargetsByType,
ITarget,
} from "interfaces/target";
type Props = {
children: ReactNode;
@ -22,6 +28,9 @@ type InitialStateType = {
lastEditedQueryPlatforms: SelectedPlatformString;
lastEditedQueryMinOsqueryVersion: string;
lastEditedQueryLoggingType: QueryLoggingOption;
lastEditedQueryDiscardData: boolean;
selectedQueryTargets: ITarget[]; // Mimicks old selectedQueryTargets still used for policies for SelectTargets.tsx and running a live query
selectedQueryTargetsByType: ISelectedTargetsByType; // New format by type for cleaner app wide state
setLastEditedQueryId: (value: number | null) => void;
setLastEditedQueryName: (value: string) => void;
setLastEditedQueryDescription: (value: string) => void;
@ -31,7 +40,10 @@ type InitialStateType = {
setLastEditedQueryPlatforms: (value: SelectedPlatformString) => void;
setLastEditedQueryMinOsqueryVersion: (value: string) => void;
setLastEditedQueryLoggingType: (value: string) => void;
setLastEditedQueryDiscardData: (value: boolean) => void;
setSelectedOsqueryTable: (tableName: string) => void;
setSelectedQueryTargets: (value: ITarget[]) => void;
setSelectedQueryTargetsByType: (value: ISelectedTargetsByType) => void;
};
export type IQueryContext = InitialStateType;
@ -48,6 +60,9 @@ const initialState = {
lastEditedQueryPlatforms: DEFAULT_QUERY.platform,
lastEditedQueryMinOsqueryVersion: DEFAULT_QUERY.min_osquery_version,
lastEditedQueryLoggingType: DEFAULT_QUERY.logging,
lastEditedQueryDiscardData: DEFAULT_QUERY.discard_data,
selectedQueryTargets: DEFAULT_TARGETS,
selectedQueryTargetsByType: DEFAULT_TARGETS_BY_TYPE,
setLastEditedQueryId: () => null,
setLastEditedQueryName: () => null,
setLastEditedQueryDescription: () => null,
@ -57,12 +72,17 @@ const initialState = {
setLastEditedQueryPlatforms: () => null,
setLastEditedQueryMinOsqueryVersion: () => null,
setLastEditedQueryLoggingType: () => null,
setLastEditedQueryDiscardData: () => null,
setSelectedOsqueryTable: () => null,
setSelectedQueryTargets: () => null,
setSelectedQueryTargetsByType: () => null,
};
const actions = {
SET_SELECTED_OSQUERY_TABLE: "SET_SELECTED_OSQUERY_TABLE",
SET_LAST_EDITED_QUERY_INFO: "SET_LAST_EDITED_QUERY_INFO",
SET_SELECTED_QUERY_TARGETS: "SET_SELECTED_QUERY_TARGETS",
SET_SELECTED_QUERY_TARGETS_BY_TYPE: "SET_SELECTED_QUERY_TARGETS_BY_TYPE",
} as const;
const reducer = (state: InitialStateType, action: any) => {
@ -113,6 +133,26 @@ const reducer = (state: InitialStateType, action: any) => {
typeof action.lastEditedQueryLoggingType === "undefined"
? state.lastEditedQueryLoggingType
: action.lastEditedQueryLoggingType,
lastEditedQueryDiscardData:
typeof action.lastEditedQueryDiscardData === "undefined"
? state.lastEditedQueryDiscardData
: action.lastEditedQueryDiscardData,
};
case actions.SET_SELECTED_QUERY_TARGETS:
return {
...state,
selectedQueryTargets:
typeof action.selectedQueryTargets === "undefined"
? state.selectedQueryTargets
: action.selectedQueryTargets,
};
case actions.SET_SELECTED_QUERY_TARGETS_BY_TYPE:
return {
...state,
selectedQueryTargetsByType:
typeof action.selectedQueryTargetsByType === "undefined"
? state.selectedQueryTargetsByType
: action.selectedQueryTargetsByType,
};
default:
return state;
@ -135,6 +175,9 @@ const QueryProvider = ({ children }: Props) => {
lastEditedQueryPlatforms: state.lastEditedQueryPlatforms,
lastEditedQueryMinOsqueryVersion: state.lastEditedQueryMinOsqueryVersion,
lastEditedQueryLoggingType: state.lastEditedQueryLoggingType,
lastEditedQueryDiscardData: state.lastEditedQueryDiscardData,
selectedQueryTargets: state.selectedQueryTargets,
selectedQueryTargetsByType: state.selectedQueryTargetsByType,
setLastEditedQueryId: (lastEditedQueryId: number | null) => {
dispatch({
type: actions.SET_LAST_EDITED_QUERY_INFO,
@ -193,6 +236,26 @@ const QueryProvider = ({ children }: Props) => {
lastEditedQueryLoggingType,
});
},
setLastEditedQueryDiscardData: (lastEditedQueryDiscardData: boolean) => {
dispatch({
type: actions.SET_LAST_EDITED_QUERY_INFO,
lastEditedQueryDiscardData,
});
},
setSelectedQueryTargets: (selectedQueryTargets: ITarget[]) => {
dispatch({
type: actions.SET_SELECTED_QUERY_TARGETS,
selectedQueryTargets,
});
},
setSelectedQueryTargetsByType: (
selectedQueryTargetsByType: ISelectedTargetsByType
) => {
dispatch({
type: actions.SET_SELECTED_QUERY_TARGETS_BY_TYPE,
selectedQueryTargetsByType,
});
},
setSelectedOsqueryTable: (tableName: string) => {
dispatch({ type: actions.SET_SELECTED_OSQUERY_TABLE, tableName });
},

View file

@ -4,7 +4,7 @@ import { filter, uniqueId } from "lodash";
import { IHost } from "interfaces/host";
import { ILabel } from "interfaces/label";
import { ITeam } from "interfaces/team";
import { ISelectedTargets } from "interfaces/target";
import { ISelectedTargetsForApi } from "interfaces/target";
import targetsAPI from "services/entities/targets";
export interface ITargetsLabels {
@ -25,7 +25,7 @@ export interface ITargetsQueryKey {
scope: string;
query: string;
queryId: number | null;
selected: ISelectedTargets;
selected: ISelectedTargetsForApi;
includeLabels: boolean;
}

View file

@ -1,95 +1,11 @@
/* Config interface is a flattened version of the fleet/config API response */
import {
IWebhookHostStatus,
IWebhookFailingPolicies,
IWebhookSoftwareVulnerabilities,
} from "interfaces/webhook";
import PropTypes from "prop-types";
import { IIntegrations } from "./integration";
export default PropTypes.shape({
org_name: PropTypes.string,
org_logo_url: PropTypes.string,
contact_url: PropTypes.string,
server_url: PropTypes.string,
live_query_disabled: PropTypes.bool,
enable_analytics: PropTypes.bool,
enable_smtp: PropTypes.bool,
configured: PropTypes.bool,
sender_address: PropTypes.string,
server: PropTypes.string,
port: PropTypes.number,
authentication_type: PropTypes.string,
user_name: PropTypes.string,
password: PropTypes.string,
enable_ssl_tls: PropTypes.bool,
authentication_method: PropTypes.string,
domain: PropTypes.string,
verify_sll_certs: PropTypes.bool,
enable_start_tls: PropTypes.bool,
entity_id: PropTypes.string,
idp_image_url: PropTypes.string,
metadata: PropTypes.string,
metadata_url: PropTypes.string,
idp_name: PropTypes.string,
enable_sso: PropTypes.bool,
enable_sso_idp_login: PropTypes.bool,
enable_jit_provisioning: PropTypes.bool,
host_expiry_enabled: PropTypes.bool,
host_expiry_window: PropTypes.number,
agent_options: PropTypes.string,
tier: PropTypes.string,
organization: PropTypes.string,
device_count: PropTypes.number,
expiration: PropTypes.string,
mdm: PropTypes.shape({
enabled_and_configured: PropTypes.bool,
apple_bm_terms_expired: PropTypes.bool,
apple_bm_enabled_and_configured: PropTypes.bool,
windows_enabled_and_configured: PropTypes.bool,
macos_updates: PropTypes.shape({
minimum_version: PropTypes.string,
deadline: PropTypes.string,
}),
}),
note: PropTypes.string,
// vulnerability_settings: PropTypes.any, TODO
enable_host_status_webhook: PropTypes.bool,
destination_url: PropTypes.string,
host_percentage: PropTypes.number,
days_count: PropTypes.number,
logging: PropTypes.shape({
debug: PropTypes.bool,
json: PropTypes.bool,
result: PropTypes.shape({
plugin: PropTypes.string,
config: PropTypes.shape({
status_log_file: PropTypes.string,
result_log_file: PropTypes.string,
enable_log_rotation: PropTypes.bool,
enable_log_compression: PropTypes.bool,
}),
}),
status: PropTypes.shape({
plugin: PropTypes.string,
config: PropTypes.shape({
status_log_file: PropTypes.string,
result_log_file: PropTypes.string,
enable_log_rotation: PropTypes.bool,
enable_log_compression: PropTypes.bool,
}),
}),
}),
email: PropTypes.shape({
backend: PropTypes.string,
config: PropTypes.shape({
region: PropTypes.string,
source_arn: PropTypes.string,
}),
}),
});
export interface ILicense {
tier: string;
device_count: number;
@ -113,6 +29,7 @@ export interface IMacOsMigrationSettings {
}
export interface IMdmConfig {
enable_disk_encryption: boolean;
enabled_and_configured: boolean;
apple_bm_default_team?: string;
apple_bm_terms_expired: boolean;
@ -196,6 +113,7 @@ export interface IConfig {
live_query_disabled: boolean;
enable_analytics: boolean;
deferred_save_host: boolean;
query_reports_disabled: boolean;
};
smtp_settings: {
enable_smtp: boolean;
@ -285,7 +203,10 @@ export interface IConfig {
};
};
mdm: IMdmConfig;
mdm_enabled?: boolean; // TODO: remove when windows MDM is released. Only used for windows MDM dev currently.
/** This is the flag that determines if the windwos mdm feature flag is enabled.
TODO: WINDOWS FEATURE FLAG: remove when windows MDM is released. Only used for windows MDM dev currently.
*/
mdm_enabled?: boolean;
}
export interface IWebhookSettings {

View file

@ -8,9 +8,10 @@ import hostQueryResult from "./campaign";
import queryStatsInterface, { IQueryStats } from "./query_stats";
import { ILicense, IDeviceGlobalConfig } from "./config";
import {
IHostMacMdmProfile,
IHostMdmProfile,
MdmEnrollmentStatus,
BootstrapPackageStatus,
DiskEncryptionStatus,
} from "./mdm";
export default PropTypes.shape({
@ -90,18 +91,16 @@ export interface IMunkiData {
version: string;
}
type MacDiskEncryptionState =
| "applied"
| "action_required"
| "enforcing"
| "failed"
| "removing_enforcement"
| null;
type MacDiskEncryptionActionRequired = "log_out" | "rotate_key" | null;
export interface IOSSettings {
disk_encryption: {
status: DiskEncryptionStatus | null;
};
}
interface IMdmMacOsSettings {
disk_encryption: MacDiskEncryptionState | null;
disk_encryption: DiskEncryptionStatus | null;
action_required: MacDiskEncryptionActionRequired | null;
}
@ -117,7 +116,8 @@ export interface IHostMdmData {
name?: string;
server_url: string | null;
id?: number;
profiles: IHostMacMdmProfile[] | null;
profiles: IHostMdmProfile[] | null;
os_settings?: IOSSettings;
macos_settings?: IMdmMacOsSettings;
macos_setup?: IMdmMacOsSetup;
}
@ -210,7 +210,7 @@ export interface IHost {
osquery_version: string;
os_version: string;
build: string;
platform_like: string;
platform_like: string; // TODO: replace with more specific union type
code_name: string;
uptime: number;
memory: number;

View file

@ -22,8 +22,6 @@ export const MDM_ENROLLMENT_STATUS = {
export type MdmEnrollmentStatus = keyof typeof MDM_ENROLLMENT_STATUS;
export type ProfileSummaryResponse = Record<MdmProfileStatus, number>;
export interface IMdmStatusCardData {
status: MdmEnrollmentStatus;
hosts: number;
@ -74,16 +72,15 @@ export type MdmProfileStatus = "verified" | "verifying" | "pending" | "failed";
export type MacMdmProfileOperationType = "remove" | "install";
export interface IHostMacMdmProfile {
export interface IHostMdmProfile {
profile_id: number;
name: string;
// identifier?: string; // TODO: add when API is updated to return this
operation_type: MacMdmProfileOperationType;
operation_type: MacMdmProfileOperationType | null;
status: MdmProfileStatus;
detail: string;
}
export type FileVaultProfileStatus =
export type DiskEncryptionStatus =
| "verified"
| "verifying"
| "action_required"
@ -91,9 +88,18 @@ export type FileVaultProfileStatus =
| "failed"
| "removing_enforcement";
// // TODO: update when list profiles API returns identifier
// export const FLEET_FILEVAULT_PROFILE_IDENTIFIER =
// "com.fleetdm.fleet.mdm.filevault";
/** Currently windows disk enxryption status will only be one of these four
values. In the future we may add more. */
export type IWindowsDiskEncryptionStatus = Extract<
DiskEncryptionStatus,
"verified" | "verifying" | "enforcing" | "failed"
>;
export const isWindowsDiskEncryptionStatus = (
status: DiskEncryptionStatus
): status is IWindowsDiskEncryptionStatus => {
return !["action_required", "removing_enforcement"].includes(status);
};
export const FLEET_FILEVAULT_PROFILE_DISPLAY_NAME = "Disk encryption";

View file

@ -3,7 +3,7 @@ import { IPack } from "./pack";
import { ISchedulableQuery } from "./schedulable_query";
import { IScheduledQueryStats } from "./scheduled_query_stats";
export interface IQueryFormData {
export interface IEditQueryFormData {
description?: string | number | boolean | undefined;
name?: string | number | boolean | undefined;
query?: string | number | boolean | undefined;
@ -35,7 +35,7 @@ export interface IQuery {
stats?: IScheduledQueryStats;
}
export interface IQueryFormFields {
export interface IEditQueryFormFields {
description: IFormField;
name: IFormField;
query: IFormField;

View file

@ -0,0 +1,12 @@
export interface IQueryReportResultRow {
host_id: number;
host_name: string;
last_fetched: string;
columns: any;
}
// Query report
export interface IQueryReport {
query_id: number;
results: IQueryReportResultRow[];
}

View file

@ -21,6 +21,7 @@ export interface ISchedulableQuery {
author_name: string;
author_email: string;
observer_can_run: boolean;
discard_data: boolean;
packs: IPack[];
stats: ISchedulableQueryStats;
}
@ -62,6 +63,7 @@ export interface ICreateQueryRequestBody {
query: string;
description?: string;
observer_can_run?: boolean;
discard_data?: boolean;
team_id?: number; // global query if ommitted
interval?: number; // default 0 means never run
platform?: SelectedPlatformString; // Might more accurately be called `platforms_to_query` comma-sepparated string of platforms to query, default all platforms if ommitted
@ -81,6 +83,7 @@ export interface IModifyQueryRequestBody
query?: string;
description?: string;
observer_can_run?: boolean;
discard_data?: boolean;
frequency?: number;
platform?: SelectedPlatformString;
min_osquery_version?: string;
@ -108,11 +111,12 @@ export interface IDeleteQueriesResponse {
deleted: number; // number of queries deleted
}
export interface IQueryFormFields {
export interface IEditQueryFormFields {
name: IFormField<string>;
description: IFormField<string>;
query: IFormField<string>;
observer_can_run: IFormField<boolean>;
discard_data: IFormField<boolean>;
frequency: IFormField<number>;
platforms: IFormField<SelectedPlatformString>;
min_osquery_version: IFormField<string>;

View file

@ -38,14 +38,29 @@ export interface ISelectTeam extends ITeam {
export type ISelectTargetsEntity = ISelectHost | ISelectLabel | ISelectTeam;
export interface ISelectedTargets {
export interface ISelectedTargetsForApi {
hosts: number[];
labels: number[];
teams: number[];
}
export interface ISelectedTargetsByType {
hosts: IHost[];
labels: ILabel[];
teams: ITeam[];
}
export interface IPackTargets {
host_ids: (number | string)[];
label_ids: (number | string)[];
team_ids: (number | string)[];
}
// TODO: Also use for testing
export const DEFAULT_TARGETS: ITarget[] = [];
export const DEFAULT_TARGETS_BY_TYPE: ISelectedTargetsByType = {
hosts: [],
labels: [],
teams: [],
};

View file

@ -44,6 +44,7 @@ export interface ITeam extends ITeamSummary {
secrets?: IEnrollSecret[];
role?: UserRole; // role value is included when the team is in the context of a user
mdm?: {
enable_disk_encryption: boolean;
macos_updates: {
minimum_version: string;
deadline: string;

View file

@ -3,7 +3,7 @@
margin-top: 20px;
padding: $pad-xxlarge;
text-align: center;
border-radius: 10px;
border-radius: $border-radius-xlarge;
z-index: 0;
align-self: center;
transform: translateY(80px);

View file

@ -1,99 +0,0 @@
import React from "react";
import paths from "router/paths";
import { buildQueryStringFromParams } from "utilities/url";
import { MdmProfileStatus, ProfileSummaryResponse } from "interfaces/mdm";
import MacSettingsIndicator from "pages/hosts/details/MacSettingsIndicator";
import { IconNames } from "components/icons";
import Spinner from "components/Spinner";
const baseClass = "aggregate-mac-settings-indicators";
interface IAggregateDisplayOption {
value: MdmProfileStatus;
text: string;
iconName: IconNames;
tooltipText: string;
}
const AGGREGATE_STATUS_DISPLAY_OPTIONS: IAggregateDisplayOption[] = [
{
value: "verified",
text: "Verified",
iconName: "success",
tooltipText:
"These hosts installed all configuration profiles. Fleet verified with osquery.",
},
{
value: "verifying",
text: "Verifying",
iconName: "success-partial",
tooltipText:
"These hosts acknowledged all MDM commands to install configuration profiles. " +
"Fleet is verifying the profiles are installed with osquery.",
},
{
value: "pending",
text: "Pending",
iconName: "pending-partial",
tooltipText:
"These hosts will receive MDM commands to install configuration profiles when the hosts come online.",
},
{
value: "failed",
text: "Failed",
iconName: "error",
tooltipText:
"These hosts failed to install configuration profiles. Click on a host to view error(s).",
},
];
interface AggregateMacSettingsIndicatorsProps {
isLoading: boolean;
teamId: number;
aggregateProfileStatusData?: ProfileSummaryResponse;
}
const AggregateMacSettingsIndicators = ({
isLoading,
teamId,
aggregateProfileStatusData,
}: AggregateMacSettingsIndicatorsProps) => {
const indicators = AGGREGATE_STATUS_DISPLAY_OPTIONS.map((status) => {
if (!aggregateProfileStatusData) return null;
const { value, text, iconName, tooltipText } = status;
const count = aggregateProfileStatusData[value];
return (
<div className="aggregate-mac-settings-indicator">
<MacSettingsIndicator
indicatorText={text}
iconName={iconName}
tooltip={{ tooltipText, position: "top" }}
/>
<a
href={`${paths.MANAGE_HOSTS}?${buildQueryStringFromParams({
team_id: teamId,
macos_settings: value,
})}`}
>
{count} hosts
</a>
</div>
);
});
if (isLoading) {
return (
<div className={baseClass}>
<Spinner className={`${baseClass}__loading-spinner`} centered={false} />
</div>
);
}
return <div className={baseClass}>{indicators}</div>;
};
export default AggregateMacSettingsIndicators;

View file

@ -1 +0,0 @@
export { default } from "./AggregateMacSettingsIndicators";

View file

@ -4,12 +4,11 @@ import { useQuery } from "react-query";
import { AppContext } from "context/app";
import SideNav from "pages/admin/components/SideNav";
import { ProfileSummaryResponse } from "interfaces/mdm";
import { API_NO_TEAM_ID, APP_CONTEXT_NO_TEAM_ID } from "interfaces/team";
import mdmAPI from "services/entities/mdm";
import OS_SETTINGS_NAV_ITEMS from "./OSSettingsNavItems";
import AggregateMacSettingsIndicators from "./AggregateMacSettingsIndicators";
import ProfileStatusAggregate from "./ProfileStatusAggregate";
import TurnOnMdmMessage from "../components/TurnOnMdmMessage";
const baseClass = "os-settings";
@ -40,9 +39,10 @@ const OSSettings = ({
data: aggregateProfileStatusData,
refetch: refetchAggregateProfileStatus,
isLoading: isLoadingAggregateProfileStatus,
} = useQuery<ProfileSummaryResponse>(
} = useQuery(
["aggregateProfileStatuses", teamId],
() => mdmAPI.getAggregateProfileStatuses(teamId),
() =>
mdmAPI.getAggregateProfileStatuses(teamId, config?.mdm_enabled ?? false),
{
refetchOnWindowFocus: false,
retry: false,
@ -50,7 +50,10 @@ const OSSettings = ({
);
// MDM is not on so show messaging for user to enable it.
if (!config?.mdm.enabled_and_configured) {
if (
!config?.mdm.enabled_and_configured &&
!config?.mdm.windows_enabled_and_configured
) {
return <TurnOnMdmMessage router={router} />;
}
@ -67,7 +70,7 @@ const OSSettings = ({
<p className={`${baseClass}__description`}>
Remotely enforce settings on macOS hosts assigned to this team.
</p>
<AggregateMacSettingsIndicators
<ProfileStatusAggregate
isLoading={isLoadingAggregateProfileStatus}
teamId={teamId}
aggregateProfileStatusData={aggregateProfileStatusData}

View file

@ -0,0 +1,95 @@
import React from "react";
import paths from "router/paths";
import { buildQueryStringFromParams } from "utilities/url";
import { MdmProfileStatus } from "interfaces/mdm";
import { ProfileStatusSummaryResponse } from "services/entities/mdm";
import Spinner from "components/Spinner";
import StatusIndicatorWithIcon, {
IndicatorStatus,
} from "components/StatusIndicatorWithIcon/StatusIndicatorWithIcon";
import AGGREGATE_STATUS_DISPLAY_OPTIONS from "./ProfileStatusAggregateOptions";
const baseClass = "profile-status-aggregate";
interface IProfileStatusCountProps {
statusIcon: IndicatorStatus;
statusValue: MdmProfileStatus;
title: string;
teamId: number;
hostCount: number;
tooltipText: string;
}
const ProfileStatusCount = ({
statusIcon,
statusValue,
teamId,
title,
hostCount,
tooltipText,
}: IProfileStatusCountProps) => {
const generateFilterHostsByStatusLink = () => {
return `${paths.MANAGE_HOSTS}?${buildQueryStringFromParams({
team_id: teamId,
macos_settings: statusValue,
})}`;
};
return (
<div className={`${baseClass}__profile-status-count`}>
<StatusIndicatorWithIcon
status={statusIcon}
value={title}
tooltip={{ tooltipText, position: "top" }}
layout="vertical"
valueClassName={`${baseClass}__status-indicator-value`}
/>
<a href={generateFilterHostsByStatusLink()}>{hostCount} hosts</a>
</div>
);
};
interface ProfileStatusAggregateProps {
isLoading: boolean;
teamId: number;
aggregateProfileStatusData?: ProfileStatusSummaryResponse;
}
const ProfileStatusAggregate = ({
isLoading,
teamId,
aggregateProfileStatusData,
}: ProfileStatusAggregateProps) => {
if (!aggregateProfileStatusData) return null;
if (isLoading) {
return (
<div className={baseClass}>
<Spinner className={`${baseClass}__loading-spinner`} centered={false} />
</div>
);
}
const indicators = AGGREGATE_STATUS_DISPLAY_OPTIONS.map((status) => {
const { value, text, iconName, tooltipText } = status;
const count = aggregateProfileStatusData[value];
return (
<ProfileStatusCount
statusIcon={iconName}
statusValue={value}
teamId={teamId}
title={text}
hostCount={count}
tooltipText={tooltipText}
/>
);
});
return <div className={baseClass}>{indicators}</div>;
};
export default ProfileStatusAggregate;

View file

@ -0,0 +1,43 @@
import { MdmProfileStatus } from "interfaces/mdm";
import { IndicatorStatus } from "components/StatusIndicatorWithIcon/StatusIndicatorWithIcon";
interface IAggregateDisplayOption {
value: MdmProfileStatus;
text: string;
iconName: IndicatorStatus;
tooltipText: string;
}
const AGGREGATE_STATUS_DISPLAY_OPTIONS: IAggregateDisplayOption[] = [
{
value: "verified",
text: "Verified",
iconName: "success",
tooltipText:
"These hosts applied all OS settings. Fleet verified with osquery.",
},
{
value: "verifying",
text: "Verifying",
iconName: "successPartial",
tooltipText:
"These hosts acknowledged all MDM commands to apply OS settings. " +
"Fleet is verifying the OS settings are applied with osquery.",
},
{
value: "pending",
text: "Pending",
iconName: "pendingPartial",
tooltipText:
"These hosts will receive MDM command to apply OS settings when the host come online.",
},
{
value: "failed",
text: "Failed",
iconName: "error",
tooltipText:
"These host failed to apply the latest OS settings. Click on a host to view error(s).",
},
];
export default AGGREGATE_STATUS_DISPLAY_OPTIONS;

View file

@ -1,16 +1,16 @@
.aggregate-mac-settings-indicators {
.profile-status-aggregate {
display: flex;
height: 94px;
border-top: 1px solid #e2e4ea;
border-bottom: 1px solid #e2e4ea;
border-left: 1px solid #e2e4ea;
border-radius: 6px;
border-radius: $border-radius-large;
&__loading-spinner {
margin: auto;
}
.aggregate-mac-settings-indicator {
&__profile-status-count {
flex-grow: 1;
display: flex;
@ -29,13 +29,17 @@
font-weight: $regular;
}
.settings-indicator {
.profile-status-indicator {
flex-direction: column;
}
}
.aggregate-mac-settings-indicator:last-child {
&__profile-status-count:last-child {
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
}
&__status-indicator-value {
font-weight: $bold;
}
}

View file

@ -0,0 +1 @@
export { default } from "./ProfileStatusAggregate";

View file

@ -31,7 +31,7 @@ const DiskEncryption = ({
const defaultShowDiskEncryption = currentTeamId
? false
: config?.mdm.macos_settings.enable_disk_encryption ?? false;
: config?.mdm.enable_disk_encryption ?? false;
const [isLoadingTeam, setIsLoadingTeam] = useState(true);
@ -67,8 +67,7 @@ const DiskEncryption = ({
enabled: currentTeamId !== 0,
select: (res) => res.team,
onSuccess: (res) => {
const enableDiskEncryption =
res.mdm?.macos_settings.enable_disk_encryption ?? false;
const enableDiskEncryption = res.mdm?.enable_disk_encryption ?? false;
setDiskEncryptionEnabled(enableDiskEncryption);
setShowAggregate(enableDiskEncryption);
setIsLoadingTeam(false);
@ -100,6 +99,19 @@ const DiskEncryption = ({
setIsLoadingTeam(false);
}
const createDescriptionText = () => {
// table is showing disk encryption status.
if (showAggregate) {
return "If turned on, hosts' disk encryption keys will be stored in Fleet. ";
}
const isWindowsFeatureFlagEnabled = config?.mdm_enabled ?? false;
const dynamicText = isWindowsFeatureFlagEnabled
? " and “BitLocker” on Windows"
: "";
return `Also known as “FileVault” on macOS${dynamicText}. If turned on, hosts' disk encryption keys will be stored in Fleet. `;
};
return (
<div className={baseClass}>
<h2>Disk encryption</h2>
@ -124,8 +136,7 @@ const DiskEncryption = ({
On
</Checkbox>
<p>
Apple calls this FileVault. If turned on, hosts&apos; disk
encryption keys will be stored in Fleet.{" "}
{createDescriptionText()}
<CustomLink
text="Learn more"
url="https://fleetdm.com/docs/using-fleet/mdm-disk-encryption"

View file

@ -2,6 +2,7 @@
h2 {
margin-top: 0;
padding-bottom: $pad-small;
margin-bottom: $pad-xxlarge;
font-size: $medium;
font-weight: $regular;
color: $core-fleet-black;

View file

@ -1,7 +1,8 @@
import React from "react";
import React, { useContext } from "react";
import { useQuery } from "react-query";
import mdmAPI, { IFileVaultSummaryResponse } from "services/entities/mdm";
import { AppContext } from "context/app";
import mdmAPI, { IDiskEncryptionSummaryResponse } from "services/entities/mdm";
import TableContainer from "components/TableContainer";
import EmptyTable from "components/EmptyTable";
@ -18,25 +19,30 @@ interface IDiskEncryptionTableProps {
currentTeamId?: number;
}
const DEFAULT_SORT_HEADER = "hosts";
const DEFAULT_SORT_DIRECTION = "asc";
const DiskEncryptionTable = ({ currentTeamId }: IDiskEncryptionTableProps) => {
const { config } = useContext(AppContext);
const {
data: diskEncryptionStatusData,
error: diskEncryptionStatusError,
} = useQuery<IFileVaultSummaryResponse, Error, IFileVaultSummaryResponse>(
} = useQuery<IDiskEncryptionSummaryResponse, Error>(
["disk-encryption-summary", currentTeamId],
() => mdmAPI.getDiskEncryptionAggregate(currentTeamId),
() => mdmAPI.getDiskEncryptionSummary(currentTeamId),
{
refetchOnWindowFocus: false,
retry: false,
}
);
const tableHeaders = generateTableHeaders();
const tableData = generateTableData(diskEncryptionStatusData, currentTeamId);
// TODO: WINDOWS FEATURE FLAG: remove this when windows feature flag is removed.
// this is used to conditianlly show "View all hosts" link in table cells.
const windowsFeatureFlagEnabled = config?.mdm_enabled ?? false;
const tableHeaders = generateTableHeaders(windowsFeatureFlagEnabled);
const tableData = generateTableData(
windowsFeatureFlagEnabled,
diskEncryptionStatusData,
currentTeamId
);
if (diskEncryptionStatusError) {
return <DataError />;
@ -53,8 +59,7 @@ const DiskEncryptionTable = ({ currentTeamId }: IDiskEncryptionTableProps) => {
isLoading={false}
showMarkAllPages={false}
isAllPagesSelected={false}
defaultSortHeader={DEFAULT_SORT_HEADER}
defaultSortDirection={DEFAULT_SORT_DIRECTION}
manualSortBy
disableTableHeader
disablePagination
disableCount

View file

@ -1,7 +1,11 @@
import React from "react";
import { FileVaultProfileStatus } from "interfaces/mdm";
import { IFileVaultSummaryResponse } from "services/entities/mdm";
import { DiskEncryptionStatus } from "interfaces/mdm";
import {
IDiskEncryptionStatusAggregate,
IDiskEncryptionSummaryResponse,
} from "services/entities/mdm";
import { DISK_ENCRYPTION_QUERY_PARAM_NAME } from "services/entities/hosts";
import TextCell from "components/TableContainer/DataTable/TextCell";
import HeaderCell from "components/TableContainer/DataTable/HeaderCell";
@ -12,7 +16,7 @@ import { IndicatorStatus } from "components/StatusIndicatorWithIcon/StatusIndica
interface IStatusCellValue {
displayName: string;
statusName: IndicatorStatus;
value: FileVaultProfileStatus;
value: DiskEncryptionStatus;
tooltip?: string | JSX.Element;
}
@ -28,6 +32,7 @@ interface ICellProps {
};
row: {
original: {
includeWindows: boolean;
status: IStatusCellValue;
teamId: number;
};
@ -72,15 +77,53 @@ const defaultTableHeaders: IDataColumn[] = [
},
},
{
title: "Hosts",
title: "macOS hosts",
Header: (cellProps: IHeaderProps) => (
<HeaderCell
value={cellProps.column.title}
isSortedDesc={cellProps.column.isSortedDesc}
disableSortBy={false}
disableSortBy
/>
),
accessor: "hosts",
disableSortBy: true,
accessor: "macosHosts",
Cell: ({
cell: { value: aggregateCount },
row: { original },
}: ICellProps) => {
return (
<div className="disk-encryption-table__aggregate-table-data">
<TextCell value={aggregateCount} formatter={(val) => <>{val}</>} />
{/* TODO: WINDOWS FEATURE FLAG: remove this conditional when windows mdm
is released. the view all UI will show in the windows column when we
release the feature. */}
{!original.includeWindows && (
<ViewAllHostsLink
className="view-hosts-link"
queryParams={{
[DISK_ENCRYPTION_QUERY_PARAM_NAME]: original.status.value,
team_id: original.teamId,
}}
/>
)}
</div>
);
},
},
];
const windowsTableHeader: IDataColumn[] = [
{
title: "Windows hosts",
Header: (cellProps: IHeaderProps) => (
<HeaderCell
value={cellProps.column.title}
isSortedDesc={cellProps.column.isSortedDesc}
disableSortBy
/>
),
disableSortBy: true,
accessor: "windowsHosts",
Cell: ({
cell: { value: aggregateCount },
row: { original },
@ -91,7 +134,7 @@ const defaultTableHeaders: IDataColumn[] = [
<ViewAllHostsLink
className="view-hosts-link"
queryParams={{
macos_settings_disk_encryption: original.status.value,
[DISK_ENCRYPTION_QUERY_PARAM_NAME]: original.status.value,
team_id: original.teamId,
}}
/>
@ -101,15 +144,17 @@ const defaultTableHeaders: IDataColumn[] = [
},
];
type StatusNames = keyof IFileVaultSummaryResponse;
type StatusEntry = [StatusNames, number];
export const generateTableHeaders = (): IDataColumn[] => {
// TODO: WINDOWS FEATURE FLAG: return all headers when windows feature flag is removed.
export const generateTableHeaders = (
includeWindows: boolean
): IDataColumn[] => {
return includeWindows
? [...defaultTableHeaders, ...windowsTableHeader]
: defaultTableHeaders;
return defaultTableHeaders;
};
const STATUS_CELL_VALUES: Record<FileVaultProfileStatus, IStatusCellValue> = {
const STATUS_CELL_VALUES: Record<DiskEncryptionStatus, IStatusCellValue> = {
verified: {
displayName: "Verified",
statusName: "success",
@ -122,8 +167,8 @@ const STATUS_CELL_VALUES: Record<FileVaultProfileStatus, IStatusCellValue> = {
statusName: "successPartial",
value: "verifying",
tooltip:
"These hosts acknowledged the MDM command to install disk encryption profile. " +
"Fleet is verifying with osquery and retrieving the disk encryption key. This may take up to one hour.",
"These hosts 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.",
},
action_required: {
displayName: "Action required (pending)",
@ -141,7 +186,7 @@ const STATUS_CELL_VALUES: Record<FileVaultProfileStatus, IStatusCellValue> = {
statusName: "pendingPartial",
value: "enforcing",
tooltip:
"These hosts will receive the MDM command to install the disk encryption profile when the hosts come online.",
"These hosts will receive the MDM command to turn on disk encryption when the hosts come online.",
},
failed: {
displayName: "Failed",
@ -153,21 +198,41 @@ const STATUS_CELL_VALUES: Record<FileVaultProfileStatus, IStatusCellValue> = {
statusName: "pendingPartial",
value: "removing_enforcement",
tooltip:
"These hosts will receive the MDM command to remove the disk encryption profile when the hosts come online.",
"These hosts will receive the MDM command to turn off disk encryption when the hosts come online.",
},
};
type StatusEntry = [DiskEncryptionStatus, IDiskEncryptionStatusAggregate];
// Order of the status column. We want the order to always be the same.
const STATUS_ORDER = [
"verified",
"verifying",
"failed",
"action_required",
"enforcing",
"removing_enforcement",
] as const;
export const generateTableData = (
data?: IFileVaultSummaryResponse,
// TODO: WINDOWS FEATURE FLAG: remove includeWindows when windows feature flag is removed.
// This is used to conditionally show "View all hosts" link in table cells.
includeWindows: boolean,
data?: IDiskEncryptionSummaryResponse,
currentTeamId?: number
) => {
if (!data) return [];
const entries = Object.entries(data) as StatusEntry[];
return entries.map(([status, numHosts]) => ({
// eslint-disable-next-line object-shorthand
const rowFromStatusEntry = (
status: DiskEncryptionStatus,
statusAggregate: IDiskEncryptionStatusAggregate
) => ({
includeWindows,
status: STATUS_CELL_VALUES[status],
hosts: numHosts,
macosHosts: statusAggregate.macos,
windowsHosts: statusAggregate.windows,
teamId: currentTeamId,
}));
});
return STATUS_ORDER.map((status) => rowFromStatusEntry(status, data[status]));
};

View file

@ -1,7 +1,4 @@
.disk-encryption-table {
padding: $pad-xxlarge;
border: 1px solid $ui-fleet-black-10;
border-radius: $border-radius;
margin-bottom: $pad-xxlarge;
.data-table-block .data-table tbody td .w250 {

View file

@ -30,7 +30,7 @@ const TurnOnMdmMessage = ({ router }: ITurnOnMdmMessageProps) => {
return (
<EmptyTable
header="Manage your macOS hosts"
header="Manage your hosts"
info={"Turn on MDM to change settings on your hosts."}
primaryButton={renderConnectButton()}
/>

View file

@ -18,7 +18,7 @@ const Advanced = ({
handleSubmit,
isUpdatingSettings,
}: IAppConfigFormProps): JSX.Element => {
const [formData, setFormData] = useState<any>({
const [formData, setFormData] = useState({
domain: appConfig.smtp_settings.domain || "",
verifySSLCerts: appConfig.smtp_settings.verify_ssl_certs || false,
enableStartTLS: appConfig.smtp_settings.enable_start_tls,
@ -26,6 +26,8 @@ const Advanced = ({
appConfig.host_expiry_settings.host_expiry_enabled || false,
hostExpiryWindow: appConfig.host_expiry_settings.host_expiry_window || 0,
disableLiveQuery: appConfig.server_settings.live_query_disabled || false,
disableQueryReports:
appConfig.server_settings.query_reports_disabled || false,
});
const {
@ -35,6 +37,7 @@ const Advanced = ({
enableHostExpiry,
hostExpiryWindow,
disableLiveQuery,
disableQueryReports,
} = formData;
const [formErrors, setFormErrors] = useState<IAppConfigFormErrors>({});
@ -69,6 +72,7 @@ const Advanced = ({
server_url: appConfig.server_settings.server_url || "",
live_query_disabled: disableLiveQuery,
enable_analytics: appConfig.server_settings.enable_analytics,
query_reports_disabled: disableQueryReports,
},
smtp_settings: {
enable_smtp: appConfig.smtp_settings.enable_smtp || false,
@ -172,6 +176,24 @@ const Advanced = ({
>
Disable live queries
</Checkbox>
<Checkbox
onChange={handleInputChange}
name="disableQueryReports"
value={disableQueryReports}
parseTarget
// TODO - update to JSX once tooltip wrapper refactor is merged
// TODO - once refactor is merged, have this and bove tooltips disappear more
// quickly to get out of users' way
tooltip={
'<p>Disabling query reports will decrease database usage, <br />\
but will prevent you from accessing query results in<br /> \
Fleet and will delete existing reports. This can also be<br />\
disabled on a per-query basis by enabling "Discard <br />\
data". <em>(Default: <b>Off</b>)</em></p>'
}
>
Disable query reports
</Checkbox>
</div>
</div>
</div>

View file

@ -1,6 +1,7 @@
import React from "react";
import Icon from "components/Icon";
import { DISK_ENCRYPTION_QUERY_PARAM_NAME } from "services/entities/hosts";
export const MANAGE_HOSTS_PAGE_FILTER_KEYS = [
"query",
@ -17,7 +18,7 @@ export const MANAGE_HOSTS_PAGE_FILTER_KEYS = [
"os_version",
"munki_issue_id",
"low_disk_space",
"macos_settings_disk_encryption",
DISK_ENCRYPTION_QUERY_PARAM_NAME,
"bootstrap_package",
] as const;

View file

@ -18,6 +18,7 @@ import labelsAPI, { ILabelsResponse } from "services/entities/labels";
import teamsAPI, { ILoadTeamsResponse } from "services/entities/teams";
import globalPoliciesAPI from "services/entities/global_policies";
import hostsAPI, {
DISK_ENCRYPTION_QUERY_PARAM_NAME,
ILoadHostsQueryKey,
ILoadHostsResponse,
ISortOption,
@ -49,7 +50,7 @@ import { IOperatingSystemVersion } from "interfaces/operating_system";
import { IPolicy, IStoredPolicyResponse } from "interfaces/policy";
import { ITeam } from "interfaces/team";
import { IEmptyTableProps } from "interfaces/empty_table";
import { FileVaultProfileStatus, BootstrapPackageStatus } from "interfaces/mdm";
import { DiskEncryptionStatus, BootstrapPackageStatus } from "interfaces/mdm";
import sortUtils from "utilities/sort";
import {
@ -232,8 +233,8 @@ const ManageHostsPage = ({
? parseInt(queryParams.low_disk_space, 10)
: undefined;
const missingHosts = queryParams?.status === "missing";
const diskEncryptionStatus: FileVaultProfileStatus | undefined =
queryParams?.macos_settings_disk_encryption;
const diskEncryptionStatus: DiskEncryptionStatus | undefined =
queryParams?.[DISK_ENCRYPTION_QUERY_PARAM_NAME];
const bootstrapPackageStatus: BootstrapPackageStatus | undefined =
queryParams?.bootstrap_package;
@ -558,7 +559,7 @@ const ManageHostsPage = ({
};
const handleChangeDiskEncryptionStatusFilter = (
newStatus: FileVaultProfileStatus
newStatus: DiskEncryptionStatus
) => {
handleResetPageIndex();
@ -569,7 +570,7 @@ const ManageHostsPage = ({
routeParams,
queryParams: {
...queryParams,
macos_settings_disk_encryption: newStatus,
[DISK_ENCRYPTION_QUERY_PARAM_NAME]: newStatus,
page: 0, // resets page index
},
})
@ -768,7 +769,7 @@ const ManageHostsPage = ({
newQueryParams.os_version = osVersion;
} else if (diskEncryptionStatus && isPremiumTier) {
// Premium feature only
newQueryParams.macos_settings_disk_encryption = diskEncryptionStatus;
newQueryParams[DISK_ENCRYPTION_QUERY_PARAM_NAME] = diskEncryptionStatus;
} else if (bootstrapPackageStatus && isPremiumTier) {
newQueryParams.bootstrap_package = bootstrapPackageStatus;
}

View file

@ -33,7 +33,7 @@
line-height: 1.5;
background-color: $ui-light-grey;
border: solid 1px $ui-fleet-black-10;
border-radius: 4px;
border-radius: $border-radius;
font-size: $small;
padding: 9.5px 12px 9.5px 36px;
color: $core-fleet-blue;
@ -70,7 +70,7 @@
color: $core-vibrant-red;
border: 1px solid $core-vibrant-red;
box-sizing: border-box;
border-radius: 4px;
border-radius: $border-radius;
&:focus {
border-color: $ui-error;

View file

@ -4,7 +4,7 @@ import { IDropdownOption } from "interfaces/dropdownOption";
// @ts-ignore
import Dropdown from "components/forms/fields/Dropdown";
import { FileVaultProfileStatus } from "interfaces/mdm";
import { DiskEncryptionStatus } from "interfaces/mdm";
const baseClass = "disk-encryption-status-filter";
@ -42,8 +42,8 @@ const DISK_ENCRYPTION_STATUS_OPTIONS: IDropdownOption[] = [
];
interface IDiskEncryptionStatusFilterProps {
diskEncryptionStatus: FileVaultProfileStatus;
onChange: (value: FileVaultProfileStatus) => void;
diskEncryptionStatus: DiskEncryptionStatus;
onChange: (value: DiskEncryptionStatus) => void;
}
const DiskEncryptionStatusFilter = ({

View file

@ -4,7 +4,7 @@
align-items: center;
padding: 6px 12px;
border: 1px solid $ui-fleet-black-25;
border-radius: 4px;
border-radius: $border-radius;
box-shadow: none;
color: $core-fleet-black;
font-size: $xx-small;

View file

@ -7,7 +7,7 @@ import {
IOperatingSystemVersion,
} from "interfaces/operating_system";
import {
FileVaultProfileStatus,
DiskEncryptionStatus,
BootstrapPackageStatus,
IMdmSolution,
MDM_ENROLLMENT_STATUS,
@ -15,7 +15,10 @@ import {
import { IMunkiIssuesAggregate } from "interfaces/macadmins";
import { ISoftware } from "interfaces/software";
import { IPolicy } from "interfaces/policy";
import { MacSettingsStatusQueryParam } from "services/entities/hosts";
import {
DISK_ENCRYPTION_QUERY_PARAM_NAME,
MacSettingsStatusQueryParam,
} from "services/entities/hosts";
import {
PLATFORM_LABEL_DISPLAY_NAMES,
@ -60,7 +63,7 @@ interface IHostsFilterBlockProps {
osVersions?: IOperatingSystemVersion[];
softwareDetails: ISoftware | null;
mdmSolutionDetails: IMdmSolution | null;
diskEncryptionStatus?: FileVaultProfileStatus;
diskEncryptionStatus?: DiskEncryptionStatus;
bootstrapPackageStatus?: BootstrapPackageStatus;
};
selectedLabel?: ILabel;
@ -68,9 +71,7 @@ interface IHostsFilterBlockProps {
handleClearRouteParam: () => void;
handleClearFilter: (omitParams: string[]) => void;
onChangePoliciesFilter: (response: PolicyResponse) => void;
onChangeDiskEncryptionStatusFilter: (
response: FileVaultProfileStatus
) => void;
onChangeDiskEncryptionStatusFilter: (response: DiskEncryptionStatus) => void;
onChangeBootstrapPackageStatusFilter: (
response: BootstrapPackageStatus
) => void;
@ -376,8 +377,8 @@ const HostsFilterBlock = ({
onChange={onChangeDiskEncryptionStatusFilter}
/>
<FilterPill
label="macOS settings: Disk encryption"
onClear={() => handleClearFilter(["macos_settings_disk_encryption"])}
label="OS settings: Disk encryption"
onClear={() => handleClearFilter([DISK_ENCRYPTION_QUERY_PARAM_NAME])}
/>
</>
);

View file

@ -417,6 +417,7 @@ const DeviceUserPage = ({
showRefetchSpinner={showRefetchSpinner}
onRefetchHost={onRefetchHost}
renderActionButtons={renderActionButtons}
osSettings={host?.mdm.os_settings}
deviceUser
/>
<TabsWrapper>
@ -489,6 +490,7 @@ const DeviceUserPage = ({
)}
{showMacSettingsModal && (
<MacSettingsModal
platform={host?.platform}
hostMDMData={host?.mdm}
onClose={toggleMacSettingsModal}
/>

View file

@ -13,6 +13,7 @@ import queryAPI from "services/entities/queries";
import teamAPI, { ILoadTeamsResponse } from "services/entities/teams";
import { AppContext } from "context/app";
import { PolicyContext } from "context/policy";
import { QueryContext } from "context/query";
import { NotificationContext } from "context/notification";
import {
IHost,
@ -26,6 +27,7 @@ import { ILabel } from "interfaces/label";
import { IHostPolicy } from "interfaces/policy";
import { IQueryStats } from "interfaces/query_stats";
import { ISoftware } from "interfaces/software";
import { DEFAULT_TARGETS_BY_TYPE } from "interfaces/target";
import { ITeam } from "interfaces/team";
import {
IListQueriesResponse,
@ -39,8 +41,13 @@ import MainContent from "components/MainContent";
import InfoBanner from "components/InfoBanner";
import BackLink from "components/BackLink";
import { normalizeEmptyValues, wrapFleetHelper } from "utilities/helpers";
import {
normalizeEmptyValues,
wrapFleetHelper,
TAGGED_TEMPLATES,
} from "utilities/helpers";
import permissions from "utilities/permissions";
import { DEFAULT_QUERY } from "utilities/constants";
import HostSummaryCard from "../cards/HostSummary";
import AboutCard from "../cards/About";
@ -65,6 +72,7 @@ import HostActionDropdown from "./HostActionsDropdown/HostActionsDropdown";
import MacSettingsModal from "../MacSettingsModal";
import BootstrapPackageModal from "./modals/BootstrapPackageModal";
import SelectQueryModal from "./modals/SelectQueryModal";
import { isSupportedPlatform } from "./modals/DiskEncryptionKeyModal/DiskEncryptionKeyModal";
const baseClass = "host-details";
@ -99,12 +107,6 @@ interface IHostDetailsSubNavItem {
pathname: string;
}
const TAGGED_TEMPLATES = {
queryByHostRoute: (hostId: number | undefined | null) => {
return `${hostId ? `?host_ids=${hostId}` : ""}`;
},
};
const HostDetailsPage = ({
route,
router,
@ -135,6 +137,7 @@ const HostDetailsPage = ({
setLastEditedQueryCritical,
setPolicyTeamId,
} = useContext(PolicyContext);
const { setSelectedQueryTargetsByType } = useContext(QueryContext);
const { renderFlash } = useContext(NotificationContext);
const handlePageError = useErrorHandler();
@ -521,12 +524,15 @@ const HostDetailsPage = ({
};
const onQueryHostCustom = () => {
setLastEditedQueryBody(DEFAULT_QUERY.query);
setSelectedQueryTargetsByType(DEFAULT_TARGETS_BY_TYPE);
router.push(
PATHS.NEW_QUERY() + TAGGED_TEMPLATES.queryByHostRoute(host?.id)
);
};
const onQueryHostSaved = (selectedQuery: ISchedulableQuery) => {
setSelectedQueryTargetsByType(DEFAULT_TARGETS_BY_TYPE);
router.push(
PATHS.EDIT_QUERY(selectedQuery.id) +
TAGGED_TEMPLATES.queryByHostRoute(host?.id)
@ -720,6 +726,7 @@ const HostDetailsPage = ({
showRefetchSpinner={showRefetchSpinner}
onRefetchHost={onRefetchHost}
renderActionButtons={renderActionButtons}
osSettings={host?.mdm.os_settings}
/>
<TabsWrapper>
<Tabs
@ -845,6 +852,7 @@ const HostDetailsPage = ({
)}
{showMacSettingsModal && (
<MacSettingsModal
platform={host?.platform}
hostMDMData={host?.mdm}
onClose={toggleMacSettingsModal}
/>
@ -852,12 +860,15 @@ const HostDetailsPage = ({
{showUnenrollMdmModal && !!host && (
<UnenrollMdmModal hostId={host.id} onClose={toggleUnenrollMdmModal} />
)}
{showDiskEncryptionModal && host && (
<DiskEncryptionKeyModal
hostId={host.id}
onCancel={() => setShowDiskEncryptionModal(false)}
/>
)}
{showDiskEncryptionModal &&
host &&
isSupportedPlatform(host.platform) && (
<DiskEncryptionKeyModal
platform={host.platform}
hostId={host.id}
onCancel={() => setShowDiskEncryptionModal(false)}
/>
)}
{showBootstrapPackageModal &&
bootstrapPackageData.details &&
bootstrapPackageData.name && (

View file

@ -9,15 +9,32 @@ import CustomLink from "components/CustomLink";
import Button from "components/buttons/Button";
import InputFieldHiddenContent from "components/forms/fields/InputFieldHiddenContent";
import DataError from "components/DataError";
import { SupportedPlatform } from "interfaces/platform";
const baseClass = "disk-encryption-key-modal";
// currently these are the only supported platforms for the disk encryption
// key modal.
export type ModalSupportedPlatform = Extract<
SupportedPlatform,
"darwin" | "windows"
>;
// Checks to see if the platform is supported by the modal.
export const isSupportedPlatform = (
platform: string
): platform is ModalSupportedPlatform => {
return ["darwin", "windows"].includes(platform);
};
interface IDiskEncryptionKeyModal {
platform: ModalSupportedPlatform;
hostId: number;
onCancel: () => void;
}
const DiskEncryptionKeyModal = ({
platform,
hostId,
onCancel,
}: IDiskEncryptionKeyModal) => {
@ -33,6 +50,18 @@ const DiskEncryptionKeyModal = ({
select: (data) => data.encryption_key.key,
});
const isMacOS = platform === "darwin";
const descriptionText = isMacOS
? "The disk encryption key refers to the FileVault recovery key for macOS."
: "The disk encryption key refers to the BitLocker recovery key for Windows.";
const recoveryText = isMacOS
? "Use this key to log in to the host if you forgot the password."
: "Use this key to unlock the encrypted drive.";
const recoveryUrl = isMacOS
? "https://fleetdm.com/docs/using-fleet/mdm-disk-encryption#reset-a-macos-hosts-password-using-the-disk-encryption-key"
: "https://fleetdm.com/docs/using-fleet/mdm-disk-encryption#unlock-a-windows-hosts-drive-using-the-disk-encryption-key";
return (
<Modal title="Disk encryption key" onExit={onCancel} className={baseClass}>
{encryptionKeyError ? (
@ -40,15 +69,12 @@ const DiskEncryptionKeyModal = ({
) : (
<>
<InputFieldHiddenContent value={encrpytionKey ?? ""} />
<p>{descriptionText}</p>
<p>
The disk encryption key refers to the FileVault recovery key for
macOS.
</p>
<p>
Use this key to log in to the host if you forgot the password.{" "}
{recoveryText}{" "}
<CustomLink
text="View recovery instructions"
url="https://fleetdm.com/docs/using-fleet/mdm-disk-encryption#reset-a-macos-hosts-password-using-the-disk-encryption-key"
url={recoveryUrl}
newTab
/>
</p>

View file

@ -42,7 +42,7 @@
&__copy-message {
background-color: $ui-light-grey;
border: solid 1px #e2e4ea;
border-radius: 10px;
border-radius: $border-radius-xlarge;
padding: 2px 6px;
}
}

View file

@ -1 +0,0 @@
export { default } from "./MacSettingsIndicator";

View file

@ -7,20 +7,28 @@ import MacSettingsTable from "./MacSettingsTable";
import { generateTableData } from "./MacSettingsTable/MacSettingsTableConfig";
interface IMacSettingsModalProps {
hostMDMData?: Pick<IHostMdmData, "profiles" | "macos_settings">;
platform?: string;
hostMDMData?: IHostMdmData;
onClose: () => void;
}
const baseClass = "mac-settings-modal";
const MacSettingsModal = ({ hostMDMData, onClose }: IMacSettingsModalProps) => {
const memoizedTableData = useMemo(() => generateTableData(hostMDMData), [
hostMDMData,
]);
const MacSettingsModal = ({
platform,
hostMDMData,
onClose,
}: IMacSettingsModalProps) => {
const memoizedTableData = useMemo(
() => generateTableData(hostMDMData, platform),
[hostMDMData, platform]
);
if (!platform) return null;
return (
<Modal
title="macOS settings"
title="OS settings"
onExit={onClose}
className={baseClass}
width="large"

View file

@ -10,7 +10,10 @@ import {
MacMdmProfileOperationType,
} from "interfaces/mdm";
import { MacSettingsTableStatusValue } from "../MacSettingsTableConfig";
import {
isMdmProfileStatus,
MacSettingsTableStatusValue,
} from "../MacSettingsTableConfig";
import TooltipContent, {
TooltipInnerContentFunc,
TooltipInnerContentOption,
@ -41,8 +44,8 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
iconName: "pending-partial",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The host will receive the MDM command to install the disk encryption profile when the " +
"host comes online."
? "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 install the configuration profile when the " +
"host comes online.",
},
@ -56,8 +59,8 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
iconName: "success",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The host turned disk encryption on and " +
"sent their key to Fleet. Fleet verified with osquery."
? "The host turned disk encryption on and sent the key to Fleet. " +
"Fleet verified with osquery."
: "The host installed the configuration profile. Fleet verified with osquery.",
},
verifying: {
@ -65,8 +68,9 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
iconName: "success-partial",
tooltip: (innerProps) =>
innerProps.isDiskEncryptionProfile
? "The host acknowledged the MDM command to install disk encryption profile. 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 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 install the configuration profile. Fleet is " +
"verifying with osquery.",
},
@ -98,9 +102,41 @@ const PROFILE_DISPLAY_CONFIG: ProfileDisplayConfig = {
},
};
type WindowsDiskEncryptionDisplayConfig = Omit<
OperationTypeOption,
"action_required"
>;
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 with osquery.",
},
verifying: {
statusText: "Verifying",
iconName: "success-partial",
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-partial",
tooltip: () =>
"The host will receive the MDM command to turn on disk encryption when the host comes online.",
},
failed: {
statusText: "Failed",
iconName: "error",
tooltip: null,
},
};
interface IMacSettingStatusCellProps {
status: MacSettingsTableStatusValue;
operationType: MacMdmProfileOperationType;
operationType: MacMdmProfileOperationType | null;
profileName: string;
}
@ -108,8 +144,18 @@ const MacSettingStatusCell = ({
status,
operationType,
profileName = "",
}: IMacSettingStatusCellProps): JSX.Element => {
const diplayOption = PROFILE_DISPLAY_CONFIG[operationType]?.[status];
}: IMacSettingStatusCellProps) => {
let displayOption: ProfileDisplayOption = null;
// windows hosts do not have an operation type at the moment and their display options are
// different than mac hosts.
if (!operationType && isMdmProfileStatus(status)) {
displayOption = WINDOWS_DISK_ENCRYPTION_DISPLAY_CONFIG[status];
}
if (operationType) {
displayOption = PROFILE_DISPLAY_CONFIG[operationType]?.[status];
}
const isDeviceUser = window.location.pathname
.toLowerCase()
@ -118,8 +164,8 @@ const MacSettingStatusCell = ({
const isDiskEncryptionProfile =
profileName === FLEET_FILEVAULT_PROFILE_DISPLAY_NAME;
if (diplayOption) {
const { statusText, iconName, tooltip } = diplayOption;
if (displayOption) {
const { statusText, iconName, tooltip } = displayOption;
const tooltipId = uniqueId();
return (
<span className={baseClass}>

View file

@ -5,20 +5,27 @@ import { IHostMdmData } from "interfaces/host";
import {
FLEET_FILEVAULT_PROFILE_DISPLAY_NAME,
// FLEET_FILEVAULT_PROFILE_IDENTIFIER,
IHostMacMdmProfile,
IHostMdmProfile,
MdmProfileStatus,
isWindowsDiskEncryptionStatus,
} from "interfaces/mdm";
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
import TruncatedTextCell from "components/TableContainer/DataTable/TruncatedTextCell";
import MacSettingStatusCell from "./MacSettingStatusCell";
import { generateWinDiskEncryptionProfile } from "../../helpers";
export interface IMacSettingsTableRow
extends Omit<IHostMacMdmProfile, "status"> {
export interface IMacSettingsTableRow extends Omit<IHostMdmProfile, "status"> {
status: MacSettingsTableStatusValue;
}
export type MacSettingsTableStatusValue = MdmProfileStatus | "action_required";
export const isMdmProfileStatus = (
status: string
): status is MdmProfileStatus => {
return status !== "action_required";
};
interface IHeaderProps {
column: {
title: string;
@ -92,20 +99,41 @@ const tableHeaders: IDataColumn[] = [
];
export const generateTableData = (
hostMDMData?: Pick<IHostMdmData, "profiles" | "macos_settings">
hostMDMData?: IHostMdmData,
platform?: string
) => {
if (!platform) return [];
let rows: IMacSettingsTableRow[] = [];
if (!hostMDMData) {
return rows;
}
if (
platform === "windows" &&
hostMDMData.os_settings?.disk_encryption.status &&
isWindowsDiskEncryptionStatus(
hostMDMData.os_settings.disk_encryption.status
)
) {
rows.push(
generateWinDiskEncryptionProfile(
hostMDMData.os_settings.disk_encryption.status
)
);
return rows;
}
const { profiles, macos_settings } = hostMDMData;
if (!profiles) {
return rows;
}
rows = profiles;
if (macos_settings?.disk_encryption === "action_required") {
if (
platform === "darwin" &&
macos_settings?.disk_encryption === "action_required"
) {
rows = profiles.map((p) => {
// TODO: this is a brittle check for the filevault profile
// it would be better to match on the identifier but it is not

View file

@ -1,12 +1,15 @@
import React from "react";
import { fireEvent, render, screen } from "@testing-library/react";
import MacSettingsIndicator from "./MacSettingsIndicator";
import ProfileStatusIndicator from "./ProfileStatusIndicator";
describe("MacSettingsIndicator", () => {
describe("ProfileStatusIndicator component", () => {
it("Renders the text and icon", () => {
const indicatorText = "test text";
render(
<MacSettingsIndicator indicatorText={indicatorText} iconName="success" />
<ProfileStatusIndicator
indicatorText={indicatorText}
iconName="success"
/>
);
const renderedIndicatorText = screen.getByText(indicatorText);
const renderedIcon = screen.getByTestId("success-icon");
@ -19,7 +22,7 @@ describe("MacSettingsIndicator", () => {
const indicatorText = "test text";
const tooltipText = "test tooltip text";
render(
<MacSettingsIndicator
<ProfileStatusIndicator
indicatorText={indicatorText}
iconName="success"
tooltip={{ tooltipText }}
@ -42,7 +45,7 @@ describe("MacSettingsIndicator", () => {
document.body.appendChild(newDiv);
};
render(
<MacSettingsIndicator
<ProfileStatusIndicator
indicatorText={indicatorText}
iconName="success"
onClick={() => {

View file

@ -4,9 +4,9 @@ import { IconNames } from "components/icons";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
const baseClass = "settings-indicator";
const baseClass = "profile-status-indicator";
export interface IMacSettingsIndicator {
export interface IProfileStatusIndicatorProps {
indicatorText: string;
iconName: IconNames;
onClick?: () => void;
@ -16,12 +16,12 @@ export interface IMacSettingsIndicator {
};
}
const MacSettingsIndicator = ({
const ProfileStatusIndicator = ({
indicatorText,
iconName,
onClick,
tooltip,
}: IMacSettingsIndicator): JSX.Element => {
}: IProfileStatusIndicatorProps) => {
const getIndicatorTextWrapped = () => {
if (onClick && tooltip?.tooltipText) {
return (
@ -103,4 +103,4 @@ const MacSettingsIndicator = ({
);
};
export default MacSettingsIndicator;
export default ProfileStatusIndicator;

View file

@ -1,4 +1,4 @@
.settings-indicator {
.profile-status-indicator {
display: flex;
gap: 4px;

Some files were not shown because too many files have changed in this diff Show more